Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7a1fb8f authored by Joshua Duong's avatar Joshua Duong
Browse files

[adbwifi] Add pairing_connection library.

Bug: 111434128
Bug: 119494503

Test: atest adb_pairing_connection_test
Change-Id: I54d68c65067809832266d6c3043b63222c98a9cd
Exempt-From-Owner-Approval: approved already
parent df8f1217
Loading
Loading
Loading
Loading
+185 −0
Original line number Diff line number Diff line
// Copyright (C) 2020 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.

cc_defaults {
    name: "libadb_pairing_connection_defaults",
    cflags: [
        "-Wall",
        "-Wextra",
        "-Wthread-safety",
        "-Werror",
    ],

    compile_multilib: "both",

    srcs: [
        "pairing_connection.cpp",
    ],
    target: {
        android: {
            version_script: "libadb_pairing_connection.map.txt",
        },
        windows: {
            compile_multilib: "first",
            enabled: true,
        },
    },
    export_include_dirs: ["include"],

    visibility: [
        "//art:__subpackages__",
        "//system/core/adb:__subpackages__",
        "//frameworks/base/services:__subpackages__",
    ],
    apex_available: [
        "com.android.adbd",
    ],

    // libadb_pairing_connection doesn't need an embedded build number.
    use_version_lib: false,

    stl: "libc++_static",

    host_supported: true,
    recovery_available: true,

    static_libs: [
        "libbase",
        "libssl",
    ],
    shared_libs: [
        "libcrypto",
        "liblog",
        "libadb_pairing_auth",
    ],
}

cc_library {
    name: "libadb_pairing_connection",
    defaults: ["libadb_pairing_connection_defaults"],

    apex_available: [
        "com.android.adbd",
    ],

    stubs: {
        symbol_file: "libadb_pairing_connection.map.txt",
        versions: ["30"],
    },

    static_libs: [
        "libadb_protos",
        // Statically link libadb_tls_connection because it is not
	// ABI-stable.
        "libadb_tls_connection",
        "libprotobuf-cpp-lite",
    ],
}

// For running atest (b/147158681)
cc_library_static {
    name: "libadb_pairing_connection_static",
    defaults: ["libadb_pairing_connection_defaults"],

    apex_available: [
        "//apex_available:platform",
    ],

    static_libs: [
        "libadb_protos_static",
        "libprotobuf-cpp-lite",
        "libadb_tls_connection_static",
    ],
}

cc_defaults {
    name: "libadb_pairing_server_defaults",
    cflags: [
        "-Wall",
        "-Wextra",
        "-Wthread-safety",
        "-Werror",
    ],

    compile_multilib: "both",

    srcs: [
        "pairing_server.cpp",
    ],
    target: {
        android: {
            version_script: "libadb_pairing_server.map.txt",
        },
    },
    export_include_dirs: ["include"],

    visibility: [
        "//art:__subpackages__",
        "//system/core/adb:__subpackages__",
        "//frameworks/base/services:__subpackages__",
    ],

    host_supported: true,
    recovery_available: true,

    stl: "libc++_static",

    static_libs: [
        "libbase",
    ],
    shared_libs: [
        "libcrypto",
        "libcrypto_utils",
        "libcutils",
        "liblog",
        "libadb_pairing_auth",
        "libadb_pairing_connection",
    ],
}

cc_library {
    name: "libadb_pairing_server",
    defaults: ["libadb_pairing_server_defaults"],

    apex_available: [
        "com.android.adbd",
    ],

    stubs: {
        symbol_file: "libadb_pairing_server.map.txt",
        versions: ["30"],
    },

    static_libs: [
        // Statically link libadb_crypto because it is not
	// ABI-stable.
        "libadb_crypto",
        "libadb_protos",
    ],
}

// For running atest (b/147158681)
cc_library_static {
    name: "libadb_pairing_server_static",
    defaults: ["libadb_pairing_server_defaults"],

    apex_available: [
        "//apex_available:platform",
    ],

    static_libs: [
        "libadb_crypto_static",
        "libadb_protos_static",
    ],
}
+130 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

#pragma once

#include <stddef.h>
#include <stdint.h>
#include <sys/cdefs.h>

#if !defined(__INTRODUCED_IN)
#define __INTRODUCED_IN(__api_level) /* nothing */
#endif

// These APIs are for the Adb pairing protocol. This protocol requires both
// sides to possess a shared secret to authenticate each other. The connection
// is over TLS, and requires that both the client and server have a valid
// certificate.
//
// This protocol is one-to-one, i.e., one PairingConnectionCtx server instance
// interacts with only one PairingConnectionCtx client instance. In other words,
// every new client instance must be bound to a new server instance.
//
// If both sides have authenticated, they will exchange their peer information
// (see #PeerInfo).
__BEGIN_DECLS
#if !defined(__ANDROID__) || __ANDROID_API__ >= 30

const uint32_t kMaxPeerInfoSize = 8192;
struct PeerInfo {
    uint8_t type;
    uint8_t data[kMaxPeerInfoSize - 1];
} __attribute__((packed));
typedef struct PeerInfo PeerInfo;
static_assert(sizeof(PeerInfo) == kMaxPeerInfoSize, "PeerInfo has weird size");

enum PeerInfoType : uint8_t {
    ADB_RSA_PUB_KEY = 0,
    ADB_DEVICE_GUID = 1,
};

struct PairingConnectionCtx;
typedef struct PairingConnectionCtx PairingConnectionCtx;
typedef void (*pairing_result_cb)(const PeerInfo*, int, void*);

// Starts the pairing connection on a separate thread.
//
// Upon completion, if the pairing was successful,
// |cb| will be called with the peer information and certificate.
// Otherwise, |cb| will be called with empty data. |fd| should already
// be opened. PairingConnectionCtx will take ownership of the |fd|.
//
// Pairing is successful if both server/client uses the same non-empty
// |pswd|, and they are able to exchange the information. |pswd| and
// |certificate| must be non-empty. start() can only be called once in the
// lifetime of this object.
//
// @param ctx the PairingConnectionCtx instance. Will abort if null.
// @param fd the fd connecting the peers. This will take ownership of fd.
// @param cb the user-provided callback that is called with the result of the
//        pairing. The callback will be called on a different thread from the
//        caller.
// @param opaque opaque userdata.
// @return true if the thread was successfully started, false otherwise. To stop
//         the connection process, destroy the instance (see
//         #pairing_connection_destroy). If false is returned, cb will not be
//         invoked. Otherwise, cb is guaranteed to be invoked, even if you
//         destroy the ctx while in the pairing process.
bool pairing_connection_start(PairingConnectionCtx* ctx, int fd, pairing_result_cb cb, void* opaque)
        __INTRODUCED_IN(30);

// Creates a new PairingConnectionCtx instance as the client.
//
// @param pswd the password to authenticate both peers. Will abort if null.
// @param pswd_len the length of pswd. Will abort if 0.
// @param peer_info the PeerInfo struct that is exchanged between peers if the
//                  pairing was successful. Will abort if null.
// @param x509_cert_pem the X.509 certificate in PEM format. Will abort if null.
// @param x509_size the size of x509_cert_pem. Will abort if 0.
// @param priv_key_pem the private key corresponding to the given X.509
//                     certificate, in PEM format. Will abort if null.
// @param priv_size the size of priv_key_pem. Will abort if 0.
// @return a new PairingConnectionCtx client instance. The caller is responsible
//         for destroying the context via #pairing_connection_destroy.
PairingConnectionCtx* pairing_connection_client_new(const uint8_t* pswd, size_t pswd_len,
                                                    const PeerInfo* peer_info,
                                                    const uint8_t* x509_cert_pem, size_t x509_size,
                                                    const uint8_t* priv_key_pem, size_t priv_size)
        __INTRODUCED_IN(30);

// Creates a new PairingConnectionCtx instance as the server.
//
// @param pswd the password to authenticate both peers. Will abort if null.
// @param pswd_len the length of pswd. Will abort if 0.
// @param peer_info the PeerInfo struct that is exchanged between peers if the
//                  pairing was successful. Will abort if null.
// @param x509_cert_pem the X.509 certificate in PEM format. Will abort if null.
// @param x509_size the size of x509_cert_pem. Will abort if 0.
// @param priv_key_pem the private key corresponding to the given X.509
//                     certificate, in PEM format. Will abort if null.
// @param priv_size the size of priv_key_pem. Will abort if 0.
// @return a new PairingConnectionCtx server instance. The caller is responsible
//         for destroying the context via #pairing_connection_destroy.
PairingConnectionCtx* pairing_connection_server_new(const uint8_t* pswd, size_t pswd_len,
                                                    const PeerInfo* peer_info,
                                                    const uint8_t* x509_cert_pem, size_t x509_size,
                                                    const uint8_t* priv_key_pem, size_t priv_size)
        __INTRODUCED_IN(30);

// Destroys the PairingConnectionCtx instance.
//
// It is safe to destroy the instance at any point in the pairing process.
//
// @param ctx the PairingConnectionCtx instance to destroy. Will abort if null.
void pairing_connection_destroy(PairingConnectionCtx* ctx) __INTRODUCED_IN(30);

#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
__END_DECLS
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

#pragma once

#include <stddef.h>
#include <stdint.h>
#include <sys/cdefs.h>

#include <functional>
#include <memory>
#include <string_view>
#include <vector>

#include "adb/pairing/pairing_connection.h"

#if !defined(__INTRODUCED_IN)
#define __INTRODUCED_IN(__api_level) /* nothing */
#endif

__BEGIN_DECLS
#if !defined(__ANDROID__) || __ANDROID_API__ >= 30

// PairingServerCtx is a wrapper around the #PairingConnectionCtx APIs,
// which handles multiple client connections.
//
// See pairing_connection_test.cpp for example usage.
//
struct PairingServerCtx;
typedef struct PairingServerCtx PairingServerCtx;

// Callback containing the result of the pairing. If #PeerInfo is null,
// then the pairing failed. Otherwise, pairing succeeded and #PeerInfo
// contains information about the peer.
typedef void (*pairing_server_result_cb)(const PeerInfo*, void*) __INTRODUCED_IN(30);

// Starts the pairing server.
//
// This call is non-blocking. Upon completion, if the pairing was successful,
// then |cb| will be called with the PeerInfo
// containing the info of the trusted peer. Otherwise, |cb| will be
// called with an empty value. Start can only be called once in the lifetime
// of this object.
//
// @param ctx the PairingServerCtx instance.
// @param cb the user-provided callback to notify the result of the pairing. See
//           #pairing_server_result_cb.
// @param opaque the opaque userdata.
// @return the port number the server is listening on. Returns 0 on failure.
uint16_t pairing_server_start(PairingServerCtx* ctx, pairing_server_result_cb cb, void* opaque)
        __INTRODUCED_IN(30);

// Creates a new PairingServerCtx instance.
//
// @param pswd the password used to authenticate the client and server.
// @param pswd_len the length of pswd.
// @param peer_info the #PeerInfo struct passed to the client on successful
//                  pairing.
// @param x509_cert_pem the X.509 certificate in PEM format. Cannot be empty.
// @param x509_size the size of x509_cert_pem.
// @param priv_key_pem the private key corresponding to the given X.509
//                     certificate, in PEM format. Cannot be empty.
// @param priv_size the size of priv_key_pem.
// @param port the port number the server should listen on. Must be within the
//             valid port range [0, 65535]. If port is 0, then the server will
//             find an open port to listen on. See #pairing_server_start to
//             obtain the port used.
// @return a new PairingServerCtx instance The caller is responsible
//         for destroying the context via #pairing_server_destroy.
PairingServerCtx* pairing_server_new(const uint8_t* pswd, size_t pswd_len,
                                     const PeerInfo* peer_info, const uint8_t* x509_cert_pem,
                                     size_t x509_size, const uint8_t* priv_key_pem,
                                     size_t priv_size, uint16_t port) __INTRODUCED_IN(30);

// Same as #pairing_server_new, except that the x509 certificate and private key
// is generated internally.
//
// @param pswd the password used to authenticate the client and server.
// @param pswd_len the length of pswd.
// @param peer_info the #PeerInfo struct passed to the client on successful
//                  pairing.
// @param port the port number the server should listen on. Must be within the
//             valid port range [0, 65535]. If port is 0, then the server will
//             find an open port to listen on. See #pairing_server_start to
//             obtain the port used.
// @return a new PairingServerCtx instance The caller is responsible
//         for destroying the context via #pairing_server_destroy.
PairingServerCtx* pairing_server_new_no_cert(const uint8_t* pswd, size_t pswd_len,
                                             const PeerInfo* peer_info, uint16_t port)
        __INTRODUCED_IN(30);

// Destroys the PairingServerCtx instance.
//
// @param ctx the PairingServerCtx instance to destroy.
void pairing_server_destroy(PairingServerCtx* ctx) __INTRODUCED_IN(30);

#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
__END_DECLS
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

#pragma once

// This file contains constants that can be used both in the pairing_connection
// code and tested in the pairing_connection_test code.
namespace adb {
namespace pairing {
namespace internal {

// The maximum number of connections the PairingServer can handle at once.
constexpr int kMaxConnections = 10;
// The maximum number of attempts the PairingServer will take before quitting.
// This is to prevent someone malicious from quickly brute-forcing every
// combination.
constexpr int kMaxPairingAttempts = 20;

}  // namespace internal
}  // namespace pairing
}  // namespace adb
+10 −0
Original line number Diff line number Diff line
LIBADB_PAIRING_CONNECTION {
  global:
    pairing_connection_client_new; # apex introduced=30
    pairing_connection_server_new; # apex introduced=30
    pairing_connection_start; # apex introduced=30
    pairing_connection_destroy; # apex introduced=30

  local:
    *;
};
Loading