diff options
author | Dan Albert <danalbert@google.com> | 2015-02-25 17:51:28 -0800 |
---|---|---|
committer | Dan Albert <danalbert@google.com> | 2015-03-09 14:06:11 -0700 |
commit | bac3474a8256cb32a29e8d46f78cad95a5502692 (patch) | |
tree | 9763c3cb2f5e640c7061cffb47d61274a37baab8 /adb/adb_auth_client.cpp | |
parent | 9b1fd969a7b7f1c6f1ed19719f21d57001d3c461 (diff) | |
download | system_core-bac3474a8256cb32a29e8d46f78cad95a5502692.zip system_core-bac3474a8256cb32a29e8d46f78cad95a5502692.tar.gz system_core-bac3474a8256cb32a29e8d46f78cad95a5502692.tar.bz2 |
Move adb to C++.
I keep trying to clean things up and needing std::strings. Might as
well just do this now.
usb_linux_client.c is going to stay as C because GCC isn't smart
enough to deal with the designated initializers it uses (though for
some reason it is in C mode).
The Darwin files are staying as C because I don't have a way to test
that they build.
The Windows files are staying as C because while I can actually build
for them, it's slow and painful.
Change-Id: I75367d29205a9049d34460032b3bb36384f43941
Diffstat (limited to 'adb/adb_auth_client.cpp')
-rw-r--r-- | adb/adb_auth_client.cpp | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp new file mode 100644 index 0000000..deb0a5d --- /dev/null +++ b/adb/adb_auth_client.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <resolv.h> +#include <stdio.h> +#include <string.h> + +#include "sysdeps.h" + +#include "adb.h" +#include "adb_auth.h" +#include "cutils/list.h" +#include "cutils/sockets.h" +#include "fdevent.h" +#include "mincrypt/rsa.h" +#include "mincrypt/sha.h" +#include "transport.h" + +#define TRACE_TAG TRACE_AUTH + + +struct adb_public_key { + struct listnode node; + RSAPublicKey key; +}; + +static const char *key_paths[] = { + "/adb_keys", + "/data/misc/adb/adb_keys", + NULL +}; + +static fdevent listener_fde; +static int framework_fd = -1; + +static void usb_disconnected(void* unused, atransport* t); +static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 }; +static atransport* usb_transport; +static bool needs_retry = false; + +static void read_keys(const char *file, struct listnode *list) +{ + FILE *f; + char buf[MAX_PAYLOAD]; + char *sep; + int ret; + + f = fopen(file, "re"); + if (!f) { + D("Can't open '%s'\n", file); + return; + } + + while (fgets(buf, sizeof(buf), f)) { + /* Allocate 4 extra bytes to decode the base64 data in-place */ + auto key = reinterpret_cast<adb_public_key*>( + calloc(1, sizeof(adb_public_key) + 4)); + if (key == nullptr) { + D("Can't malloc key\n"); + break; + } + + sep = strpbrk(buf, " \t"); + if (sep) + *sep = '\0'; + + ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4); + if (ret != sizeof(key->key)) { + D("%s: Invalid base64 data ret=%d\n", file, ret); + free(key); + continue; + } + + if (key->key.len != RSANUMWORDS) { + D("%s: Invalid key len %d\n", file, key->key.len); + free(key); + continue; + } + + list_add_tail(list, &key->node); + } + + fclose(f); +} + +static void free_keys(struct listnode *list) +{ + struct listnode *item; + + while (!list_empty(list)) { + item = list_head(list); + list_remove(item); + free(node_to_item(item, struct adb_public_key, node)); + } +} + +static void load_keys(struct listnode *list) +{ + const char* path; + const char** paths = key_paths; + struct stat buf; + + list_init(list); + + while ((path = *paths++)) { + if (!stat(path, &buf)) { + D("Loading keys from '%s'\n", path); + read_keys(path, list); + } + } +} + +int adb_auth_generate_token(void *token, size_t token_size) +{ + FILE *f; + int ret; + + f = fopen("/dev/urandom", "re"); + if (!f) + return 0; + + ret = fread(token, token_size, 1, f); + + fclose(f); + return ret * token_size; +} + +int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen) +{ + struct listnode *item; + struct listnode key_list; + int ret = 0; + + if (siglen != RSANUMBYTES) + return 0; + + load_keys(&key_list); + + list_for_each(item, &key_list) { + adb_public_key* key = node_to_item(item, struct adb_public_key, node); + ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE); + if (ret) + break; + } + + free_keys(&key_list); + + return ret; +} + +static void usb_disconnected(void* unused, atransport* t) +{ + D("USB disconnect\n"); + remove_transport_disconnect(usb_transport, &usb_disconnect); + usb_transport = NULL; + needs_retry = false; +} + +static void adb_auth_event(int fd, unsigned events, void *data) +{ + char response[2]; + int ret; + + if (events & FDE_READ) { + ret = unix_read(fd, response, sizeof(response)); + if (ret <= 0) { + D("Framework disconnect\n"); + if (usb_transport) + fdevent_remove(&usb_transport->auth_fde); + framework_fd = -1; + } + else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { + if (usb_transport) + adb_auth_verified(usb_transport); + } + } +} + +void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t) +{ + char msg[MAX_PAYLOAD]; + int ret; + + if (!usb_transport) { + usb_transport = t; + add_transport_disconnect(t, &usb_disconnect); + } + + if (framework_fd < 0) { + D("Client not connected\n"); + needs_retry = true; + return; + } + + if (key[len - 1] != '\0') { + D("Key must be a null-terminated string\n"); + return; + } + + ret = snprintf(msg, sizeof(msg), "PK%s", key); + if (ret >= (signed)sizeof(msg)) { + D("Key too long. ret=%d", ret); + return; + } + D("Sending '%s'\n", msg); + + ret = unix_write(framework_fd, msg, ret); + if (ret < 0) { + D("Failed to write PK, errno=%d\n", errno); + return; + } + + fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t); + fdevent_add(&t->auth_fde, FDE_READ); +} + +static void adb_auth_listener(int fd, unsigned events, void *data) +{ + struct sockaddr addr; + socklen_t alen; + int s; + + alen = sizeof(addr); + + s = adb_socket_accept(fd, &addr, &alen); + if (s < 0) { + D("Failed to accept: errno=%d\n", errno); + return; + } + + framework_fd = s; + + if (needs_retry) { + needs_retry = false; + send_auth_request(usb_transport); + } +} + +void adb_auth_init(void) +{ + int fd, ret; + + fd = android_get_control_socket("adbd"); + if (fd < 0) { + D("Failed to get adbd socket\n"); + return; + } + fcntl(fd, F_SETFD, FD_CLOEXEC); + + ret = listen(fd, 4); + if (ret < 0) { + D("Failed to listen on '%d'\n", fd); + return; + } + + fdevent_install(&listener_fde, fd, adb_auth_listener, NULL); + fdevent_add(&listener_fde, FDE_READ); +} |