Skip to content
File

Blob: src/workerd/server/channel-token.h

cpp90 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/io/io-channels.h>
8#include <workerd/server/channel-token.capnp.h>
9 
10namespace workerd::server {
11 
12// Helper class to encode channel tokens for workerd.
13//
14// This is an internal implementation helper for `Server` (in `server.h`), separated out into its
15// own module solely for unit testing purposes. Nobody except `Server` should use this interface
16// directly.
17//
18// Note that all `Frankenvalue`s here are expected to contain cap tables holding live instances
19// of `SubrequestChannel` and `ActorClassChannel`.
20class ChannelTokenHandler {
21 public:
22 // Callbacks implemented by `Server` (in `server.h`) to resolve entrypoint designators to live
23 // objects.
24 //
25 // (In theory, we could have a decodeChannelToken() method that returns the service name,
26 // entrypoint name, and props as a struct, but this would require extra string copies and would
27 // also make abstractions a little messier in server.c++.)
28 class Resolver {
29 public:
30 virtual kj::Own<IoChannelFactory::SubrequestChannel> resolveEntrypoint(
31 kj::StringPtr serviceName, kj::Maybe<kj::StringPtr> entrypoint, Frankenvalue props) = 0;
32 
33 virtual kj::Own<IoChannelFactory::ActorClassChannel> resolveActorClass(
34 kj::StringPtr serviceName, kj::Maybe<kj::StringPtr> entrypoint, Frankenvalue props) = 0;
35 };
36 
37 explicit ChannelTokenHandler(Resolver& resolver);
38 
39 // Helpers to implement `IoChannelFactory::{SubrequestChannel,ActorClassChannel}::getToken()`.
40 kj::Array<byte> encodeSubrequestChannelToken(IoChannelFactory::ChannelTokenUsage usage,
41 kj::StringPtr serviceName,
42 kj::Maybe<kj::StringPtr> entrypoint,
43 Frankenvalue& props);
44 kj::Array<byte> encodeActorClassChannelToken(IoChannelFactory::ChannelTokenUsage usage,
45 kj::StringPtr serviceName,
46 kj::Maybe<kj::StringPtr> entrypoint,
47 Frankenvalue& props);
48 
49 // Helpers to implement `IoChannelFactory::{subrequestChannel,actorClass}FromToken()`.
50 kj::Own<IoChannelFactory::SubrequestChannel> decodeSubrequestChannelToken(
51 IoChannelFactory::ChannelTokenUsage usage, kj::ArrayPtr<const byte> token);
52 kj::Own<IoChannelFactory::ActorClassChannel> decodeActorClassChannelToken(
53 IoChannelFactory::ChannelTokenUsage usage, kj::ArrayPtr<const byte> token);
54 
55 private:
56 // Annoyingly the OpenSSL/BoringSSL headers don't seem to define these as static constants.
57 static constexpr uint AES_KEY_SIZE = 32;
58 static constexpr uint AES_IV_SIZE = 12;
59 static constexpr uint AES_MAC_SIZE = 16;
60 
61 // The key ID is the 16-byte prefix of a SHA-256 hash of the secret key.
62 static constexpr uint KEY_ID_SIZE = 16;
63 
64 Resolver& resolver;
65 byte tokenKey[AES_KEY_SIZE];
66 byte keyId[KEY_ID_SIZE];
67 
68 struct TokenHeader {
69 uint32_t magic;
70 byte iv[AES_IV_SIZE];
71 byte keyId[KEY_ID_SIZE];
72 };
73 static_assert(sizeof(TokenHeader) == 32);
74 
75 // Implementation for both `encode` methods.
76 kj::Array<byte> encodeChannelTokenImpl(ChannelToken::Type type,
77 IoChannelFactory::ChannelTokenUsage usage,
78 kj::StringPtr serviceName,
79 kj::Maybe<kj::StringPtr> entrypoint,
80 Frankenvalue& props);
81 
82 // Implementation that dynamically returns either SubrequestChannel or ActorClassChannel, which
83 // both happen to inherit CapTableEntry. The caller will immediately downcast to the right type.
84 kj::Own<Frankenvalue::CapTableEntry> decodeChannelTokenImpl(ChannelToken::Type type,
85 IoChannelFactory::ChannelTokenUsage usage,
86 kj::ArrayPtr<const byte> token);
87};
88 
89} // namespace workerd::server