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

Commit 4293e322 authored by Joshua Duong's avatar Joshua Duong
Browse files

[adbwifi] Add tls_connection library.

Bug: 111434128, 119494503, 119493510

Test: atest adb_tls_connection_test
Exempt-From-Owner-Approval: yolo?
Change-Id: Ie9b629e4cb955702cec890bbb89a6a762e4b71b3
parent ef28ca4c
Loading
Loading
Loading
Loading

adb/tls/Android.bp

0 → 100644
+75 −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_tls_connection_defaults",
    cflags: [
        "-Wall",
        "-Wextra",
        "-Wthread-safety",
        "-Werror",
    ],

    compile_multilib: "both",

    srcs: [
        "adb_ca_list.cpp",
        "tls_connection.cpp",
    ],
    target: {
        windows: {
            compile_multilib: "first",
            enabled: true,
        },
    },
    export_include_dirs: ["include"],

    host_supported: true,
    recovery_available: true,

    visibility: [
        "//system/core/adb:__subpackages__",
    ],

    stl: "libc++_static",

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

cc_library {
    name: "libadb_tls_connection",
    defaults: ["libadb_tls_connection_defaults"],

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

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

    apex_available: [
        "//apex_available:platform",
    ],
}
+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.
 */

#include "adb/tls/adb_ca_list.h"

#include <iomanip>
#include <sstream>
#include <vector>

#include <android-base/logging.h>
#include <android-base/strings.h>
#include <openssl/ssl.h>

namespace adb {
namespace tls {

namespace {

// CA issuer identifier to distinguished embedded keys. Also has version
// information appended to the end of the string (e.g. "AdbKey-0").
static constexpr int kAdbKeyIdentifierNid = NID_organizationName;
static constexpr char kAdbKeyIdentifierPrefix[] = "AdbKey-";
static constexpr int kAdbKeyVersion = 0;

// Where we store the actual data
static constexpr int kAdbKeyValueNid = NID_commonName;

// TODO: Remove this once X509_NAME_add_entry_by_NID is fixed to use const unsigned char*
int X509_NAME_add_entry_by_NID_const(X509_NAME* name, int nid, int type, const unsigned char* bytes,
                                     int len, int loc, int set) {
    return X509_NAME_add_entry_by_NID(name, nid, type, const_cast<unsigned char*>(bytes), len, loc,
                                      set);
}

bool IsHexDigit(char c) {
    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}

// Wrapper around X509_NAME_get_text_by_NID that first calculates the size
// of the string. Returns empty string on failure.
std::optional<std::string> GetX509NameTextByNid(X509_NAME* name, int nid) {
    // |len| is the len of the text excluding the final null
    int len = X509_NAME_get_text_by_NID(name, nid, nullptr, -1);
    if (len <= 0) {
        return {};
    }

    // Include the space for the final null byte
    std::vector<char> buf(len + 1, '\0');
    CHECK(X509_NAME_get_text_by_NID(name, nid, buf.data(), buf.size()));
    return buf.data();
}

}  // namespace

// Takes an encoded public key and generates a X509_NAME that can be used in
// TlsConnection::SetClientCAList(), to allow the client to figure out which of
// its keys it should try to use in the TLS handshake.
bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key) {
    // "O=AdbKey-0;CN=<key>;"
    CHECK(!key.empty());

    std::string identifier = kAdbKeyIdentifierPrefix;
    identifier += std::to_string(kAdbKeyVersion);
    bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
    CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC,
                                           reinterpret_cast<const uint8_t*>(identifier.data()),
                                           identifier.size(), -1, 0));

    CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyValueNid, MBSTRING_ASC,
                                           reinterpret_cast<const uint8_t*>(key.data()), key.size(),
                                           -1, 0));
    return name;
}

// Parses a CA issuer and returns the encoded key, if any.
std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer) {
    CHECK(issuer);

    auto buf = GetX509NameTextByNid(issuer, kAdbKeyIdentifierNid);
    if (!buf || !android::base::StartsWith(*buf, kAdbKeyIdentifierPrefix)) {
        return {};
    }

    return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
}

std::string SHA256BitsToHexString(std::string_view sha256) {
    CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
    std::stringstream ss;
    ss << std::uppercase << std::setfill('0') << std::hex;
    // Convert to hex-string representation
    for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
        ss << std::setw(2) << (0x00FF & sha256[i]);
    }
    return ss.str();
}

std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
    if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
        return {};
    }

    std::string result;
    for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
        auto bytestr = std::string(sha256_str.substr(i * 2, 2));
        if (!IsHexDigit(bytestr[0]) || !IsHexDigit(bytestr[1])) {
            LOG(ERROR) << "SHA256 string has invalid non-hex chars";
            return {};
        }
        result += static_cast<char>(std::stol(bytestr, nullptr, 16));
    }
    return result;
}

}  // namespace tls
}  // namespace adb
+47 −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 <openssl/base.h>
#include <optional>
#include <string>

// These APIs is used to embed adbd's known public keys into client-allowed CA
// issuer list that can indicate to the client which key to use.
namespace adb {
namespace tls {

// Takes an encoded public key and generates a X509_NAME that can be used in
// TlsConnection::SetClientCAList(), to allow the client to figure out which of
// its keys it should try to use in the TLS handshake. This is guaranteed to
// return a valid X509_NAME, given a non-empty key.
bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key);

// Parses a CA issuer and returns the encoded key, if any. On failure, returns
// nullopt.
std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer);

// Converts SHA256 bits to a hex string representation. |sha256| must be exactly
// |SHA256_DIGEST_LENGTH| in size.
std::string SHA256BitsToHexString(std::string_view sha256);

// Converts a valid SHA256 hex string to the actual bits. Returns nullopt on
// failure.
std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str);

}  // namespace tls
}  // namespace adb
+127 −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 <string_view>
#include <vector>

#include <android-base/unique_fd.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>

namespace adb {
namespace tls {

class TlsConnection {
  public:
    // This class will require both client and server to exchange valid
    // certificates.
    enum class Role {
        Server,
        Client,
    };

    enum class TlsError : uint8_t {
        Success = 0,
        // An error indicating that we rejected the peer's certificate.
        CertificateRejected,
        // An error indicating that the peer rejected our certificate.
        PeerRejectedCertificate,
        // Add more if needed
        UnknownFailure,
    };

    using CertVerifyCb = std::function<int(X509_STORE_CTX*)>;
    using SetCertCb = std::function<int(SSL*)>;

    virtual ~TlsConnection() = default;

    // Adds a trusted certificate to the list for the SSL connection.
    // During the handshake phase, it will check the list of trusted certificates.
    // The connection will fail if the peer's certificate is not in the list. Use
    // |EnableCertificateVerification(false)| to disable certificate
    // verification.
    //
    // Returns true if |cert| was successfully added, false otherwise.
    virtual bool AddTrustedCertificate(std::string_view cert) = 0;

    // Sets a custom certificate verify callback. |cb| must return 1 if the
    // certificate is trusted. Otherwise, return 0 if not. Note that |cb| is
    // only used if EnableCertificateVerification(false).
    virtual void SetCertVerifyCallback(CertVerifyCb cb) = 0;

    // Configures a client |ca_list| that the server sends to the client in the
    // CertificateRequest message.
    virtual void SetClientCAList(STACK_OF(X509_NAME) * ca_list) = 0;

    // Sets a callback that will be called to select a certificate. See
    // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_cb
    // for more details.
    virtual void SetCertificateCallback(SetCertCb cb) = 0;

    // Exports a value derived from the master secret used in the TLS
    // connection. This value should be used alongside any PAKE to ensure the
    // peer is the intended peer. |length| is the requested length for the
    // keying material. This is only valid after |DoHandshake| succeeds.
    virtual std::vector<uint8_t> ExportKeyingMaterial(size_t length) = 0;

    // Enable client-side check on whether server accepted the handshake. In TLS
    // 1.3, client will not know the server rejected the handshake until after
    // performing a read operation. Basically, this will perform an
    // SSL_peek right after the handshake and see whether that succeeds.
    //
    // IMPORTANT: this will only work if the protocol is a server-speaks-first
    // type. Enabling this for the server is a no-op. This is disabled by
    // default.
    virtual void EnableClientPostHandshakeCheck(bool enable) = 0;

    // Starts the handshake process. Returns TlsError::Success if handshake
    // succeeded.
    virtual TlsError DoHandshake() = 0;

    // Reads |size| bytes and returns the data. The returned data has either
    // size |size| or zero, in which case the read failed.
    virtual std::vector<uint8_t> ReadFully(size_t size) = 0;

    // Overloaded ReadFully method, which accepts a buffer for writing in.
    // Returns true iff exactly |size| amount of data was written into |buf|,
    // false otherwise.
    virtual bool ReadFully(void* buf, size_t size) = 0;

    // Writes |size| bytes. Returns true if all |size| bytes were read.
    // Returns false otherwise.
    virtual bool WriteFully(std::string_view data) = 0;

    // Create a new TlsConnection instance. |cert| and |priv_key| cannot be
    // empty.
    static std::unique_ptr<TlsConnection> Create(Role role, std::string_view cert,
                                                 std::string_view priv_key,
                                                 android::base::borrowed_fd fd);

    // Helper to set the certificate and key strings to a SSL client/server.
    // Useful when in the set-certificate callback.
    static bool SetCertAndKey(SSL* ssl, std::string_view cert_chain, std::string_view priv_key);

  protected:
    TlsConnection() = default;
};  // TlsConnection

}  // namespace tls
}  // namespace adb
+42 −0
Original line number Diff line number Diff line
//
// Copyright (C) 2019 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_test {
    name: "adb_tls_connection_test",
    srcs: [
        "adb_ca_list_test.cpp",
        "tls_connection_test.cpp",
    ],

    compile_multilib: "first",

    shared_libs: [
        "libbase",
        "libcrypto",
        "libcrypto_utils",
        "libssl",
    ],

    // Let's statically link them so we don't have to install it onto the
    // system image for testing.
    static_libs: [
        "libadb_crypto_static",
        "libadb_protos_static",
        "libadb_tls_connection_static",
    ],

    test_suites: ["device-tests"],
}
Loading