Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 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 | |
Yabin Cui | 19bec5b | 2015-09-22 15:52:57 -0700 | [diff] [blame] | 17 | #define TRACE_TAG AUTH |
Dan Albert | db6fe64 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 18 | |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 19 | #include "adb.h" |
Dan Albert | db6fe64 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 20 | #include "adb_auth.h" |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 21 | #include "adb_io.h" |
Josh Gao | b51193a | 2019-06-28 13:50:37 -0700 | [diff] [blame] | 22 | #include "fdevent/fdevent.h" |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 23 | #include "sysdeps.h" |
| 24 | #include "transport.h" |
Dan Albert | db6fe64 | 2015-03-19 15:21:08 -0700 | [diff] [blame] | 25 | |
Dan Albert | b302d12 | 2015-02-24 15:51:19 -0800 | [diff] [blame] | 26 | #include <resolv.h> |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 27 | #include <stdio.h> |
| 28 | #include <string.h> |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 29 | #include <iomanip> |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 30 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 31 | #include <algorithm> |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 32 | #include <memory> |
| 33 | |
| 34 | #include <android-base/file.h> |
| 35 | #include <android-base/strings.h> |
| 36 | #include <crypto_utils/android_pubkey.h> |
Mattias Nissler | a947b49 | 2016-03-31 16:32:09 +0200 | [diff] [blame] | 37 | #include <openssl/obj_mac.h> |
| 38 | #include <openssl/rsa.h> |
| 39 | #include <openssl/sha.h> |
| 40 | |
Josh Gao | 9528df2 | 2018-05-14 11:14:33 -0700 | [diff] [blame] | 41 | static fdevent* listener_fde = nullptr; |
| 42 | static fdevent* framework_fde = nullptr; |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 43 | static auto& framework_mutex = *new std::mutex(); |
| 44 | static int framework_fd GUARDED_BY(framework_mutex) = -1; |
| 45 | static auto& connected_keys GUARDED_BY(framework_mutex) = *new std::vector<std::string>; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 46 | |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 47 | static void adb_disconnected(void* unused, atransport* t); |
| 48 | static struct adisconnect adb_disconnect = {adb_disconnected, nullptr}; |
| 49 | static atransport* adb_transport; |
Benoit Goby | d592d6c | 2013-01-15 19:59:14 -0800 | [diff] [blame] | 50 | static bool needs_retry = false; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 51 | |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 52 | bool auth_required = true; |
| 53 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 54 | bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig, |
| 55 | std::string* auth_key) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 56 | static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr }; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 57 | |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 58 | for (const auto& path : key_paths) { |
| 59 | if (access(path, R_OK) == 0) { |
| 60 | LOG(INFO) << "Loading keys from " << path; |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 61 | std::string content; |
| 62 | if (!android::base::ReadFileToString(path, &content)) { |
| 63 | PLOG(ERROR) << "Couldn't read " << path; |
| 64 | continue; |
| 65 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 66 | |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 67 | for (const auto& line : android::base::Split(content, "\n")) { |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 68 | if (line.empty()) continue; |
| 69 | *auth_key = line; |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 70 | // TODO: do we really have to support both ' ' and '\t'? |
| 71 | char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t"); |
| 72 | if (sep) *sep = '\0'; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 73 | |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 74 | // b64_pton requires one additional byte in the target buffer for |
| 75 | // decoding to succeed. See http://b/28035006 for details. |
| 76 | uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1]; |
Josh Gao | 0560feb | 2019-01-22 19:36:15 -0800 | [diff] [blame] | 77 | if (b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 78 | LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path; |
| 79 | continue; |
| 80 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 81 | |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 82 | RSA* key = nullptr; |
| 83 | if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) { |
| 84 | LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path; |
| 85 | continue; |
| 86 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 87 | |
Josh Gao | 67ac379 | 2016-10-06 13:31:44 -0700 | [diff] [blame] | 88 | bool verified = |
| 89 | (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size, |
Josh Gao | 839b932 | 2018-02-05 18:49:10 -0800 | [diff] [blame] | 90 | reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(), |
| 91 | key) == 1); |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 92 | RSA_free(key); |
| 93 | if (verified) return true; |
| 94 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 95 | } |
| 96 | } |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 97 | auth_key->clear(); |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 98 | return false; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 101 | static bool adbd_send_key_message_locked(std::string_view msg_type, std::string_view key) |
| 102 | REQUIRES(framework_mutex) { |
| 103 | if (framework_fd < 0) { |
| 104 | LOG(ERROR) << "Client not connected to send msg_type " << msg_type; |
| 105 | return false; |
| 106 | } |
| 107 | std::string msg = std::string(msg_type) + std::string(key); |
| 108 | int msg_len = msg.length(); |
| 109 | if (msg_len >= static_cast<int>(MAX_FRAMEWORK_PAYLOAD)) { |
| 110 | LOG(ERROR) << "Key too long (" << msg_len << ")"; |
| 111 | return false; |
| 112 | } |
| 113 | |
| 114 | LOG(DEBUG) << "Sending '" << msg << "'"; |
| 115 | if (!WriteFdExactly(framework_fd, msg.c_str(), msg_len)) { |
| 116 | PLOG(ERROR) << "Failed to write " << msg_type; |
| 117 | return false; |
| 118 | } |
| 119 | return true; |
| 120 | } |
| 121 | |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 122 | static bool adbd_auth_generate_token(void* token, size_t token_size) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 123 | FILE* fp = fopen("/dev/urandom", "re"); |
| 124 | if (!fp) return false; |
| 125 | bool okay = (fread(token, token_size, 1, fp) == 1); |
| 126 | fclose(fp); |
| 127 | return okay; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 128 | } |
| 129 | |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 130 | static void adb_disconnected(void* unused, atransport* t) { |
| 131 | LOG(INFO) << "ADB disconnect"; |
| 132 | adb_transport = nullptr; |
Benoit Goby | d592d6c | 2013-01-15 19:59:14 -0800 | [diff] [blame] | 133 | needs_retry = false; |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 134 | { |
| 135 | std::lock_guard<std::mutex> lock(framework_mutex); |
| 136 | if (framework_fd >= 0) { |
| 137 | adbd_send_key_message_locked("DC", t->auth_key); |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 138 | } |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 139 | connected_keys.erase(std::remove(connected_keys.begin(), connected_keys.end(), t->auth_key), |
| 140 | connected_keys.end()); |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 141 | } |
Benoit Goby | d592d6c | 2013-01-15 19:59:14 -0800 | [diff] [blame] | 142 | } |
| 143 | |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 144 | static void framework_disconnected() { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 145 | LOG(INFO) << "Framework disconnect"; |
Josh Gao | 9528df2 | 2018-05-14 11:14:33 -0700 | [diff] [blame] | 146 | if (framework_fde) { |
| 147 | fdevent_destroy(framework_fde); |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 148 | { |
| 149 | std::lock_guard<std::mutex> lock(framework_mutex); |
| 150 | framework_fd = -1; |
| 151 | } |
Josh Gao | 9528df2 | 2018-05-14 11:14:33 -0700 | [diff] [blame] | 152 | } |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 153 | } |
| 154 | |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 155 | static void adbd_auth_event(int fd, unsigned events, void*) { |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 156 | if (events & FDE_READ) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 157 | char response[2]; |
| 158 | int ret = unix_read(fd, response, sizeof(response)); |
Vince Harron | 8212542 | 2014-09-25 21:51:15 -0700 | [diff] [blame] | 159 | if (ret <= 0) { |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 160 | framework_disconnected(); |
| 161 | } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 162 | if (adb_transport) { |
| 163 | adbd_auth_verified(adb_transport); |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 164 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | } |
| 168 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 169 | void adbd_auth_confirm_key(atransport* t) { |
Michael Groover | c046900 | 2018-12-28 20:35:37 -0800 | [diff] [blame] | 170 | if (!adb_transport) { |
| 171 | adb_transport = t; |
| 172 | t->AddDisconnect(&adb_disconnect); |
Benoit Goby | c002888 | 2013-04-01 17:39:06 -0700 | [diff] [blame] | 173 | } |
Benoit Goby | d592d6c | 2013-01-15 19:59:14 -0800 | [diff] [blame] | 174 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 175 | { |
| 176 | std::lock_guard<std::mutex> lock(framework_mutex); |
| 177 | if (framework_fd < 0) { |
| 178 | LOG(ERROR) << "Client not connected"; |
| 179 | needs_retry = true; |
| 180 | return; |
| 181 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 182 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 183 | adbd_send_key_message_locked("PK", t->auth_key); |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 184 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 185 | } |
| 186 | |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 187 | static void adbd_auth_listener(int fd, unsigned events, void* data) { |
Josh Gao | 782d8d4 | 2016-08-23 15:41:56 -0700 | [diff] [blame] | 188 | int s = adb_socket_accept(fd, nullptr, nullptr); |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 189 | if (s < 0) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 190 | PLOG(ERROR) << "Failed to accept"; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 191 | return; |
| 192 | } |
| 193 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 194 | { |
| 195 | std::lock_guard<std::mutex> lock(framework_mutex); |
| 196 | if (framework_fd >= 0) { |
| 197 | LOG(WARNING) << "adb received framework auth socket connection again"; |
| 198 | framework_disconnected(); |
| 199 | } |
| 200 | |
| 201 | framework_fd = s; |
| 202 | framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr); |
| 203 | fdevent_add(framework_fde, FDE_READ); |
| 204 | |
| 205 | if (needs_retry) { |
| 206 | needs_retry = false; |
| 207 | send_auth_request(adb_transport); |
| 208 | } |
| 209 | |
| 210 | // if a client connected before the framework was available notify the framework of the |
| 211 | // connected key now. |
| 212 | if (!connected_keys.empty()) { |
| 213 | for (const auto& key : connected_keys) { |
| 214 | adbd_send_key_message_locked("CK", key); |
| 215 | } |
| 216 | } |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 217 | } |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 218 | } |
Josh Gao | 7a8c7cb | 2016-02-23 18:05:57 -0800 | [diff] [blame] | 219 | |
Michael Groover | 02b7427 | 2019-04-25 18:33:35 -0700 | [diff] [blame] | 220 | void adbd_notify_framework_connected_key(atransport* t) { |
| 221 | if (!adb_transport) { |
| 222 | adb_transport = t; |
| 223 | t->AddDisconnect(&adb_disconnect); |
| 224 | } |
| 225 | { |
| 226 | std::lock_guard<std::mutex> lock(framework_mutex); |
| 227 | if (std::find(connected_keys.begin(), connected_keys.end(), t->auth_key) == |
| 228 | connected_keys.end()) { |
| 229 | connected_keys.push_back(t->auth_key); |
| 230 | } |
| 231 | if (framework_fd >= 0) { |
| 232 | adbd_send_key_message_locked("CK", t->auth_key); |
| 233 | } |
Benoit Goby | d592d6c | 2013-01-15 19:59:14 -0800 | [diff] [blame] | 234 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 235 | } |
| 236 | |
Pavel Labath | 0bdb867 | 2015-03-17 11:03:36 -0700 | [diff] [blame] | 237 | void adbd_cloexec_auth_socket() { |
| 238 | int fd = android_get_control_socket("adbd"); |
| 239 | if (fd == -1) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 240 | PLOG(ERROR) << "Failed to get adbd socket"; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 241 | return; |
| 242 | } |
Nick Kralevich | 777523e | 2014-07-18 20:57:35 -0700 | [diff] [blame] | 243 | fcntl(fd, F_SETFD, FD_CLOEXEC); |
Pavel Labath | 0bdb867 | 2015-03-17 11:03:36 -0700 | [diff] [blame] | 244 | } |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 245 | |
Pavel Labath | 0bdb867 | 2015-03-17 11:03:36 -0700 | [diff] [blame] | 246 | void adbd_auth_init(void) { |
| 247 | int fd = android_get_control_socket("adbd"); |
| 248 | if (fd == -1) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 249 | PLOG(ERROR) << "Failed to get adbd socket"; |
Pavel Labath | 0bdb867 | 2015-03-17 11:03:36 -0700 | [diff] [blame] | 250 | return; |
| 251 | } |
| 252 | |
| 253 | if (listen(fd, 4) == -1) { |
Elliott Hughes | 801066a | 2016-06-29 17:42:01 -0700 | [diff] [blame] | 254 | PLOG(ERROR) << "Failed to listen on '" << fd << "'"; |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 255 | return; |
| 256 | } |
| 257 | |
Yi Kong | 86e6718 | 2018-07-13 18:15:16 -0700 | [diff] [blame] | 258 | listener_fde = fdevent_create(fd, adbd_auth_listener, nullptr); |
Josh Gao | 9528df2 | 2018-05-14 11:14:33 -0700 | [diff] [blame] | 259 | fdevent_add(listener_fde, FDE_READ); |
Benoit Goby | 2cc19e4 | 2012-04-12 12:23:49 -0700 | [diff] [blame] | 260 | } |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 261 | |
| 262 | void send_auth_request(atransport* t) { |
| 263 | LOG(INFO) << "Calling send_auth_request..."; |
| 264 | |
| 265 | if (!adbd_auth_generate_token(t->token, sizeof(t->token))) { |
| 266 | PLOG(ERROR) << "Error generating token"; |
| 267 | return; |
| 268 | } |
| 269 | |
| 270 | apacket* p = get_apacket(); |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 271 | p->msg.command = A_AUTH; |
| 272 | p->msg.arg0 = ADB_AUTH_TOKEN; |
| 273 | p->msg.data_length = sizeof(t->token); |
Josh Gao | 839b932 | 2018-02-05 18:49:10 -0800 | [diff] [blame] | 274 | p->payload.assign(t->token, t->token + sizeof(t->token)); |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 275 | send_packet(p, t); |
| 276 | } |
| 277 | |
Josh Gao | 03eba90 | 2017-07-26 11:06:55 -0700 | [diff] [blame] | 278 | void adbd_auth_verified(atransport* t) { |
| 279 | LOG(INFO) << "adb client authorized"; |
Josh Gao | eac2058 | 2016-10-05 19:02:29 -0700 | [diff] [blame] | 280 | handle_online(t); |
| 281 | send_connect(t); |
| 282 | } |