Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
adb: Add public key authentification
Browse files Browse the repository at this point in the history
Secure adb using a public key authentication, to allow USB debugging
only from authorized hosts.

When a device is connected to an unauthorized host, the adb daemon sends
the user public key to the device. A popup is shown to ask the user to
allow debugging once or permanantly from the host. The public key is
installed on the device in the later case. Other keys may be installed
at build time.

On the host, the user public/private key pair is automatically generated,
if it does not exist, when the adb daemon starts and is stored in
$HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed,
the ADB_KEYS_PATH env variable may be set to a :-separated (; under
Windows) list of private keys, e.g. company-wide or vendor keys.

On the device, vendors public keys are installed at build time in
/adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys.

ADB Protocol change:
If the device needs to authenticate the host, it replies to CNXN
packets with an AUTH packet. The AUTH packet payload is a random token.
The host signs the token with one of its private keys and sends an AUTH(0)
packet. If the signature verification succeeds, the device replies with
a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so
that the host can retry with another private key. Once the host has tried
all its keys, it can send an AUTH(1) packet with a public key as
payload. adbd then sends the public key to the framework (if it has been
started) for confirmation.

Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
  • Loading branch information
benoitgoby committed Aug 23, 2012
1 parent 42a1e6c commit d5fcafa
Show file tree
Hide file tree
Showing 8 changed files with 882 additions and 22 deletions.
22 changes: 16 additions & 6 deletions adb/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,34 @@ ifeq ($(HOST_OS),linux)
USB_SRCS := usb_linux.c
EXTRA_SRCS := get_my_path_linux.c
LOCAL_LDLIBS += -lrt -lncurses -lpthread
LOCAL_SHARED_LIBRARIES := libcrypto
endif

ifeq ($(HOST_OS),darwin)
USB_SRCS := usb_osx.c
EXTRA_SRCS := get_my_path_darwin.c
LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_LDLIBS += -lpthread -lcrypto -framework CoreFoundation -framework IOKit -framework Carbon
endif

ifeq ($(HOST_OS),freebsd)
USB_SRCS := usb_libusb.c
EXTRA_SRCS := get_my_path_freebsd.c
LOCAL_LDLIBS += -lpthread -lusb
LOCAL_SHARED_LIBRARIES := libcrypto
endif

ifeq ($(HOST_OS),windows)
USB_SRCS := usb_windows.c
EXTRA_SRCS := get_my_path_windows.c
EXTRA_STATIC_LIBS := AdbWinApi
EXTRA_SRCS := get_my_path_windows.c ../libcutils/list.c
EXTRA_STATIC_LIBS := AdbWinApi libcrypto_static
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread
LOCAL_LDLIBS += -lpthread -lgdi32
LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32
LOCAL_LDLIBS += -lws2_32 -lgdi32
USE_SYSDEPS_WIN32 := 1
LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
Expand All @@ -57,6 +59,7 @@ LOCAL_SRC_FILES := \
transport_usb.c \
commandline.c \
adb_client.c \
adb_auth_host.c \
sockets.c \
services.c \
file_sync_client.c \
Expand All @@ -65,6 +68,7 @@ LOCAL_SRC_FILES := \
utils.c \
usb_vendors.c

LOCAL_C_INCLUDES += external/openssl/include

ifneq ($(USE_SYSDEPS_WIN32),)
LOCAL_SRC_FILES += sysdeps_win32.c
Expand Down Expand Up @@ -104,6 +108,7 @@ LOCAL_SRC_FILES := \
transport.c \
transport_local.c \
transport_usb.c \
adb_auth_client.c \
sockets.c \
services.c \
file_sync_service.c \
Expand All @@ -127,7 +132,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)

LOCAL_STATIC_LIBRARIES := libcutils libc
LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
include $(BUILD_EXECUTABLE)


Expand All @@ -146,6 +151,7 @@ LOCAL_SRC_FILES := \
transport_usb.c \
commandline.c \
adb_client.c \
adb_auth_host.c \
sockets.c \
services.c \
file_sync_client.c \
Expand All @@ -165,9 +171,13 @@ LOCAL_CFLAGS := \
-D_XOPEN_SOURCE \
-D_GNU_SOURCE

LOCAL_C_INCLUDES += external/openssl/include

LOCAL_MODULE := adb

LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils

LOCAL_SHARED_LIBRARIES := libcrypto

include $(BUILD_EXECUTABLE)
endif
128 changes: 114 additions & 14 deletions adb/adb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "sysdeps.h"
#include "adb.h"
#include "adb_auth.h"

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

Expand All @@ -46,6 +47,8 @@ ADB_MUTEX_DEFINE( D_lock );

int HOST = 0;

static int auth_enabled = 0;

#if !ADB_HOST
static const char *adb_device_banner = "device";
#endif
Expand Down Expand Up @@ -100,6 +103,7 @@ void adb_trace_init(void)
{ "transport", TRACE_TRANSPORT },
{ "jdwp", TRACE_JDWP },
{ "services", TRACE_SERVICES },
{ "auth", TRACE_AUTH },
{ NULL, 0 }
};

Expand Down Expand Up @@ -203,19 +207,21 @@ void put_apacket(apacket *p)
free(p);
}

void handle_online(void)
void handle_online(atransport *t)
{
D("adb: online\n");
t->online = 1;
}

void handle_offline(atransport *t)
{
D("adb: offline\n");
//Close the associated usb
t->online = 0;
run_transport_disconnects(t);
}

#if TRACE_PACKETS
#if DEBUG_PACKETS
#define DUMPMAX 32
void print_packet(const char *label, apacket *p)
{
Expand All @@ -230,6 +236,7 @@ void print_packet(const char *label, apacket *p)
case A_OKAY: tag = "OKAY"; break;
case A_CLSE: tag = "CLSE"; break;
case A_WRTE: tag = "WRTE"; break;
case A_AUTH: tag = "AUTH"; break;
default: tag = "????"; break;
}

Expand All @@ -251,7 +258,7 @@ void print_packet(const char *label, apacket *p)
}
x++;
}
fprintf(stderr, tag);
fputs(tag, stderr);
}
#endif

Expand Down Expand Up @@ -315,11 +322,70 @@ static void send_connect(atransport *t)
cp->msg.data_length = fill_connect_data((char *)cp->data,
sizeof(cp->data));
send_packet(cp, t);
#if ADB_HOST
/* XXX why sleep here? */
// allow the device some time to respond to the connect message
adb_sleep_ms(1000);
#endif
}

static void send_auth_request(atransport *t)
{
D("Calling send_auth_request\n");
apacket *p;
int ret;

ret = adb_auth_generate_token(t->token, sizeof(t->token));
if (ret != sizeof(t->token)) {
D("Error generating token ret=%d\n", ret);
return;
}

p = get_apacket();
memcpy(p->data, t->token, ret);
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_TOKEN;
p->msg.data_length = ret;
send_packet(p, t);
}

static void send_auth_response(uint8_t *token, size_t token_size, atransport *t)
{
D("Calling send_auth_response\n");
apacket *p = get_apacket();
int ret;

ret = adb_auth_sign(t->key, token, token_size, p->data);
if (!ret) {
D("Error signing the token\n");
put_apacket(p);
return;
}

p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_SIGNATURE;
p->msg.data_length = ret;
send_packet(p, t);
}

static void send_auth_publickey(atransport *t)
{
D("Calling send_auth_publickey\n");
apacket *p = get_apacket();
int ret;

ret = adb_auth_get_userkey(p->data, sizeof(p->data));
if (!ret) {
D("Failed to get user public key\n");
put_apacket(p);
return;
}

p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
p->msg.data_length = ret;
send_packet(p, t);
}

void adb_auth_verified(atransport *t)
{
handle_online(t);
send_connect(t);
}

static char *connection_state_name(atransport *t)
Expand Down Expand Up @@ -451,13 +517,42 @@ void handle_packet(apacket *p, atransport *t)
t->connection_state = CS_OFFLINE;
handle_offline(t);
}

parse_banner((char*) p->data, t);
handle_online();
if(!HOST) send_connect(t);

if (HOST || !auth_enabled) {
handle_online(t);
if(!HOST) send_connect(t);
} else {
send_auth_request(t);
}
break;

case A_AUTH:
if (p->msg.arg0 == ADB_AUTH_TOKEN) {
t->key = adb_auth_nextkey(t->key);
if (t->key) {
send_auth_response(p->data, p->msg.data_length, t);
} else {
/* No more private keys to try, send the public key */
send_auth_publickey(t);
}
} else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
adb_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
if (t->failed_auth_attempts++ > 10)
adb_sleep_ms(1000);
send_auth_request(t);
}
} else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
adb_auth_confirm_key(p->data, p->msg.data_length, t);
}
break;

case A_OPEN: /* OPEN(local-id, 0, "destination") */
if(t->connection_state != CS_OFFLINE) {
if (t->online) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
s = create_local_service_socket(name);
Expand All @@ -473,7 +568,7 @@ void handle_packet(apacket *p, atransport *t)
break;

case A_OKAY: /* READY(local-id, remote-id, "") */
if(t->connection_state != CS_OFFLINE) {
if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
if(s->peer == 0) {
s->peer = create_remote_socket(p->msg.arg0, t);
Expand All @@ -485,15 +580,15 @@ void handle_packet(apacket *p, atransport *t)
break;

case A_CLSE: /* CLOSE(local-id, remote-id, "") */
if(t->connection_state != CS_OFFLINE) {
if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
s->close(s);
}
}
break;

case A_WRTE:
if(t->connection_state != CS_OFFLINE) {
if (t->online) {
if((s = find_local_socket(p->msg.arg1))) {
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length;
Expand Down Expand Up @@ -1014,13 +1109,18 @@ int adb_main(int is_daemon, int server_port)
usb_vendors_init();
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
adb_auth_init();

char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
if(install_listener(local_name, "*smartsocket*", NULL)) {
exit(1);
}
#else
property_get("ro.adb.secure", value, "0");
auth_enabled = !strcmp(value, "1");
if (auth_enabled)
adb_auth_init();

/* don't listen on a port (default 5037) if running in secure mode */
/* don't run as root if we are running in secure mode */
Expand Down
14 changes: 12 additions & 2 deletions adb/adb.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
#define A_WRTE 0x45545257
#define A_AUTH 0x48545541

#define A_VERSION 0x01000000 // ADB protocol version

#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information

#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server
#define ADB_SERVER_VERSION 30 // Increment this when we want to force users to start a new adb server

typedef struct amessage amessage;
typedef struct apacket apacket;
Expand Down Expand Up @@ -165,6 +166,8 @@ typedef enum transport_type {
kTransportHost,
} transport_type;

#define TOKEN_SIZE 20

struct atransport
{
atransport *next;
Expand All @@ -181,6 +184,7 @@ struct atransport
int ref_count;
unsigned sync_token;
int connection_state;
int online;
transport_type type;

/* usb handle or socket fd as needed */
Expand All @@ -198,6 +202,11 @@ struct atransport
/* a list of adisconnect callbacks called when the transport is kicked */
int kicked;
adisconnect disconnects;

void *key;
unsigned char token[TOKEN_SIZE];
fdevent auth_fde;
unsigned failed_auth_attempts;
};


Expand Down Expand Up @@ -349,6 +358,7 @@ typedef enum {
TRACE_SYSDEPS,
TRACE_JDWP, /* 0x100 */
TRACE_SERVICES,
TRACE_AUTH,
} AdbTrace;

#if ADB_TRACE
Expand Down Expand Up @@ -408,7 +418,7 @@ void adb_qemu_trace(const char* fmt, ...);
#endif


#if !TRACE_PACKETS
#if !DEBUG_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif

Expand Down
Loading

0 comments on commit d5fcafa

Please sign in to comment.