1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*
* 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 kAdbKeyIdentifierV0[] = "AdbKey-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*
// https://boringssl-review.googlesource.com/c/boringssl/+/39764
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 std::nullopt;
}
// 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 std::make_optional(std::string(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 = kAdbKeyIdentifierV0;
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) {
return std::nullopt;
}
// Check for supported versions
if (*buf == kAdbKeyIdentifierV0) {
return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
}
return std::nullopt;
}
std::string SHA256BitsToHexString(std::string_view sha256) {
CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
std::stringstream ss;
auto* u8 = reinterpret_cast<const uint8_t*>(sha256.data());
ss << std::uppercase << std::setfill('0') << std::hex;
// Convert to hex-string representation
for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
// Need to cast to something bigger than one byte, or
// stringstream will interpret it as a char value.
ss << std::setw(2) << static_cast<uint16_t>(u8[i]);
}
return ss.str();
}
std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
return std::nullopt;
}
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 std::nullopt;
}
result += static_cast<char>(std::stol(bytestr, nullptr, 16));
}
return result;
}
} // namespace tls
} // namespace adb
|