Commit cf0a7779 authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

device/fido: add some tunnel server utilities.

These functions allow a limited range of domains to be encoded in 22
bits for inclusion in BLE adverts.

BUG=1002262

Change-Id: I122af89cada6e6416d3a647b3ecdc724a8289f47
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2340063
Commit-Queue: Adam Langley <agl@chromium.org>
Reviewed-by: default avatarMartin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#796592}
parent 320cb6fc
......@@ -6,6 +6,7 @@
#include "base/bits.h"
#include "base/numerics/safe_math.h"
#include "base/strings/string_number_conversions.h"
#include "components/cbor/reader.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
......@@ -21,6 +22,7 @@
#include "third_party/boringssl/src/include/openssl/hkdf.h"
#include "third_party/boringssl/src/include/openssl/obj.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
#include "url/gurl.h"
namespace {
......@@ -47,6 +49,36 @@ bool ConstructNonce(uint32_t counter, base::span<uint8_t, 12> out_nonce) {
namespace device {
namespace cablev2 {
namespace tunnelserver {
GURL GetURL(uint32_t domain, Action action, base::span<const uint8_t, 16> id) {
std::string ret = "wss://";
static const char kBase32Chars[33] = "abcdefghijklmnopqrstuvwxyz234567";
ret.push_back(kBase32Chars[(domain >> 17) & 0x1f]);
ret.push_back(kBase32Chars[(domain >> 12) & 0x1f]);
ret.push_back(kBase32Chars[(domain >> 7) & 0x1f]);
ret.push_back(kBase32Chars[(domain >> 2) & 0x1f]);
ret.push_back('.');
static const char kTLDs[4][5] = {"com", "org", "net", "info"};
ret += kTLDs[domain & 3];
switch (action) {
case Action::kNew:
ret += "/cable/new/";
break;
case Action::kConnect:
ret += "/cable/connect/";
break;
}
ret += base::HexEncode(id);
const GURL url(ret);
DCHECK(url.is_valid());
return url;
}
} // namespace tunnelserver
base::Optional<std::vector<uint8_t>> EncodePaddedCBORMap(
cbor::Value::MapValue map) {
base::Optional<std::vector<uint8_t>> cbor_bytes =
......
......@@ -19,9 +19,61 @@
#include "device/fido/fido_constants.h"
#include "third_party/boringssl/src/include/openssl/base.h"
class GURL;
namespace device {
namespace cablev2 {
namespace tunnelserver {
// Base32Ord converts |c| into its base32 value, as defined in
// https://tools.ietf.org/html/rfc4648#section-6.
constexpr uint32_t Base32Ord(char c) {
if (c >= 'a' && c <= 'z') {
return c - 'a';
} else if (c >= '2' && c <= '7') {
return 26 + c - '2';
} else {
__builtin_unreachable();
}
}
// TLD enumerates the set of possible top-level domains that a tunnel server can
// use.
enum class TLD {
COM = 0,
ORG = 1,
NET = 2,
INFO = 3,
};
// EncodeDomain converts a domain name, in the form of a four-letter, base32
// domain plus a TLD, into a 22-bit value.
constexpr uint32_t EncodeDomain(const char label[5], TLD tld) {
const uint32_t tld_value = static_cast<uint32_t>(tld);
if (tld_value > 3 || label[4] != 0) {
__builtin_unreachable();
}
return ((Base32Ord(label[0]) << 15 | Base32Ord(label[1]) << 10 |
Base32Ord(label[2]) << 5 | Base32Ord(label[3]))
<< 2) |
tld_value;
}
// Action enumerates the two possible requests that can be made of a tunnel
// server: to create a new tunnel or to connect to an existing one.
enum class Action {
kNew,
kConnect,
};
// GetURL converts a 22-bit tunnel server domain (as encoded by |EncodeDomain|),
// an action, and a tunnel ID, into a WebSockets-based URL.
COMPONENT_EXPORT(DEVICE_FIDO)
GURL GetURL(uint32_t domain, Action action, base::span<const uint8_t, 16> id);
} // namespace tunnelserver
// EncodePaddedCBORMap encodes the given map and pads it to 256 bytes in such a
// way that |DecodePaddedCBORMap| can decode it. The padding is done on the
// assumption that the returned bytes will be encrypted and the encoded size of
......
......@@ -8,12 +8,23 @@
#include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/obj.h"
#include "url/gurl.h"
namespace device {
namespace cablev2 {
namespace {
TEST(CableV2Encoding, TunnelServerURLs) {
// Test that a domain name survives an encode-decode round trip.
constexpr uint32_t encoded =
tunnelserver::EncodeDomain("abcd", tunnelserver::TLD::NET);
uint8_t tunnel_id[16] = {0};
const GURL url =
tunnelserver::GetURL(encoded, tunnelserver::Action::kNew, tunnel_id);
EXPECT_TRUE(url.spec().find("//abcd.net/") != std::string::npos) << url;
}
TEST(CableV2Encoding, PaddedCBOR) {
cbor::Value::MapValue map;
base::Optional<std::vector<uint8_t>> encoded =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment