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
17#define TRACE_TAG AUTH
18
19#include "adb.h"
20#include "adb_auth.h"
21#include "fdevent.h"
22#include "sysdeps.h"
23#include "transport.h"
24
25#include <resolv.h>
26#include <stdio.h>
27#include <string.h>
28
29#include <memory>
30
31#include <android-base/file.h>
32#include <android-base/strings.h>
33#include <crypto_utils/android_pubkey.h>
34#include <openssl/obj_mac.h>
35#include <openssl/rsa.h>
36#include <openssl/sha.h>
37
38static fdevent listener_fde;
39static fdevent framework_fde;
40static int framework_fd = -1;
41
42static void usb_disconnected(void* unused, atransport* t);
43static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
44static atransport* usb_transport;
45static bool needs_retry = false;
46
47bool auth_required = true;
48
49bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len) {
50    static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
51
52    for (const auto& path : key_paths) {
53        if (access(path, R_OK) == 0) {
54            LOG(INFO) << "Loading keys from " << path;
55
56            std::string content;
57            if (!android::base::ReadFileToString(path, &content)) {
58                PLOG(ERROR) << "Couldn't read " << path;
59                continue;
60            }
61
62            for (const auto& line : android::base::Split(content, "\n")) {
63                // TODO: do we really have to support both ' ' and '\t'?
64                char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
65                if (sep) *sep = '\0';
66
67                // b64_pton requires one additional byte in the target buffer for
68                // decoding to succeed. See http://b/28035006 for details.
69                uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
70                if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
71                    LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
72                    continue;
73                }
74
75                RSA* key = nullptr;
76                if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
77                    LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path;
78                    continue;
79                }
80
81                bool verified =
82                    (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
83                                reinterpret_cast<const uint8_t*>(sig), sig_len, key) == 1);
84                RSA_free(key);
85                if (verified) return true;
86            }
87        }
88    }
89    return false;
90}
91
92static bool adbd_auth_generate_token(void* token, size_t token_size) {
93    FILE* fp = fopen("/dev/urandom", "re");
94    if (!fp) return false;
95    bool okay = (fread(token, token_size, 1, fp) == 1);
96    fclose(fp);
97    return okay;
98}
99
100static void usb_disconnected(void* unused, atransport* t) {
101    LOG(INFO) << "USB disconnect";
102    usb_transport = NULL;
103    needs_retry = false;
104}
105
106static void framework_disconnected() {
107    LOG(INFO) << "Framework disconnect";
108    fdevent_remove(&framework_fde);
109    framework_fd = -1;
110}
111
112static void adbd_auth_event(int fd, unsigned events, void*) {
113    if (events & FDE_READ) {
114        char response[2];
115        int ret = unix_read(fd, response, sizeof(response));
116        if (ret <= 0) {
117            framework_disconnected();
118        } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
119            if (usb_transport) {
120                adbd_auth_verified(usb_transport);
121            }
122        }
123    }
124}
125
126void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) {
127    if (!usb_transport) {
128        usb_transport = t;
129        t->AddDisconnect(&usb_disconnect);
130    }
131
132    if (framework_fd < 0) {
133        LOG(ERROR) << "Client not connected";
134        needs_retry = true;
135        return;
136    }
137
138    if (key[len - 1] != '\0') {
139        LOG(ERROR) << "Key must be a null-terminated string";
140        return;
141    }
142
143    char msg[MAX_PAYLOAD_V1];
144    int msg_len = snprintf(msg, sizeof(msg), "PK%s", key);
145    if (msg_len >= static_cast<int>(sizeof(msg))) {
146        LOG(ERROR) << "Key too long (" << msg_len << ")";
147        return;
148    }
149    LOG(DEBUG) << "Sending '" << msg << "'";
150
151    if (unix_write(framework_fd, msg, msg_len) == -1) {
152        PLOG(ERROR) << "Failed to write PK";
153        return;
154    }
155}
156
157static void adbd_auth_listener(int fd, unsigned events, void* data) {
158    int s = adb_socket_accept(fd, nullptr, nullptr);
159    if (s < 0) {
160        PLOG(ERROR) << "Failed to accept";
161        return;
162    }
163
164    if (framework_fd >= 0) {
165        LOG(WARNING) << "adb received framework auth socket connection again";
166        framework_disconnected();
167    }
168
169    framework_fd = s;
170    fdevent_install(&framework_fde, framework_fd, adbd_auth_event, nullptr);
171    fdevent_add(&framework_fde, FDE_READ);
172
173    if (needs_retry) {
174        needs_retry = false;
175        send_auth_request(usb_transport);
176    }
177}
178
179void adbd_cloexec_auth_socket() {
180    int fd = android_get_control_socket("adbd");
181    if (fd == -1) {
182        PLOG(ERROR) << "Failed to get adbd socket";
183        return;
184    }
185    fcntl(fd, F_SETFD, FD_CLOEXEC);
186}
187
188void adbd_auth_init(void) {
189    int fd = android_get_control_socket("adbd");
190    if (fd == -1) {
191        PLOG(ERROR) << "Failed to get adbd socket";
192        return;
193    }
194
195    if (listen(fd, 4) == -1) {
196        PLOG(ERROR) << "Failed to listen on '" << fd << "'";
197        return;
198    }
199
200    fdevent_install(&listener_fde, fd, adbd_auth_listener, NULL);
201    fdevent_add(&listener_fde, FDE_READ);
202}
203
204void send_auth_request(atransport* t) {
205    LOG(INFO) << "Calling send_auth_request...";
206
207    if (!adbd_auth_generate_token(t->token, sizeof(t->token))) {
208        PLOG(ERROR) << "Error generating token";
209        return;
210    }
211
212    apacket* p = get_apacket();
213    memcpy(p->data, t->token, sizeof(t->token));
214    p->msg.command = A_AUTH;
215    p->msg.arg0 = ADB_AUTH_TOKEN;
216    p->msg.data_length = sizeof(t->token);
217    send_packet(p, t);
218}
219
220void adbd_auth_verified(atransport* t) {
221    LOG(INFO) << "adb client authorized";
222    handle_online(t);
223    send_connect(t);
224}
225