Appendix: Transparency Log
The protocol for communication with the transparency log service.
Overview
Private Cloud Compute’s transparency log is designed to enable security researchers to audit the integrity and contents of the log.
Log server protocol
The transparency log uses Protobuf encoding for most objects, but TLS 1.3 Presentation Language for objects that require deterministic encoding.
For all objects in the log:
Timestamps are specified in milliseconds elapsed since 00:00:00 UTC on January 1, 1970.
Hashes are calculated using SHA-256.
The value for
ProtocolVersionfields is 3.The value for
Applicationfields isPRIVATE_CLOUD_COMPUTE = 5.
PCC nodes use the following protocol to get proofs to include with attestations sent to client devices.
message ATLogProofRequest {
ProtocolVersion version = 1;
Application application = 2;
bytes identifier = 3;
}
message ATLogProofResponse {
Status status = 1;
ATLogProofs proofs = 3;
}
message ATLogProofs {
// Inclusion proof for this data if it exists in the log.
LogEntry inclusionProof = 1;
// If the inclusion proof isn't to a milestone root, this is included to prove consistency with a recent milestone.
LogConsistency milestoneConsistency = 2;
}
message LogConsistency {
SignedObject startSLH = 3; // Signed Log Head of a milestone root.
SignedObject endSLH = 4; // Matches SLH in `inclusionProof`.
repeated bytes proofHashes = 5;
// Inclusion proof of the `endSLH` in the PAT, and the PAT head in the TLT.
LogEntry patInclusionProof = 8;
LogEntry tltInclusionProof = 9;
}
// The value and inclusion proof of a log leaf.
message LogEntry {
LogType logType = 1; // value is 5 for the PCC log
SignedObject slh = 2;
repeated bytes hashesOfPeersInPathToRoot = 3; // ordered with leaf at position 0, root-1 at end
bytes nodeBytes = 4; // for the PCC log this is a ChangeLogNodeV2 wrapping a TLS encoded ATLeafData struct
uint64 nodePosition = 5;
NodeType nodeType = 6; // value is 7 for the PCC log
}
message LogHead {
uint64 logBeginningMs = 1;
uint64 logSize = 2;
bytes logHeadHash = 3;
uint64 revision = 4;
LogType logType = 5;
Application application = 6;
uint64 treeId = 7;
uint64 timestampMs = 8;
}
message SignedObject {
// Parse as `LogHead` for PCC cases.
bytes object = 1;
Signature signature = 2;
}
message Signature {
bytes signature = 1;
// This is a hash of the DER encoded public key used to verify the signature.
bytes signingKeySPKIHash = 2;
SignatureAlgorithm algorithm = 3;
enum SignatureAlgorithm {
UNKNOWN = 0;
ECDSA_SHA256 = 1;
}
}
enum Status {
UNKNOWN_STATUS = 0;
OK = 1;
MUTATION_PENDING = 3;
ALREADY_EXISTS = 4;
INTERNAL_ERROR = 5;
INVALID_REQUEST = 6;
NOT_FOUND = 7;
}The client makes this request daily for milestone roots. The request does not include Protobuf content. Instead, it specifies the known tree ID and last known milestone revision in HTTP headers.
message MilestoneRootsResponse {
Status status = 1;
// SLH at the client's last known revision, or revision 0 after a tree roll.
SignedObject startSLH = 4;
repeated MilestoneConsistency milestones = 5;
// Inclusion proof of a recent milestone in the PAT, and the PAT head in the TLT.
LogEntry patInclusionProof = 8;
LogEntry tltInclusionProof = 9;
}
message MilestoneConsistency {
// This is the end SLH of the consistency proof. The start SLH is the previous milestone
// in the list of proofs, or startSLH for the first proof in the list.
SignedObject milestoneSLH = 4;
repeated bytes proofHashes = 5;
}Log entry format
PCC transparency log entries consist of a Protocol Buffer wrapper around a record encoded using TLS 1.3 Presentation Language.
message ChangeLogNodeV2 {
bytes value = 1;
}
opaque HashValue<1..255>;
enum {
(255)
} ExtensionType;
// In extensions vectors, there might only be one `Extension` of any `ExtensionType`; Extensions are ordered by `ExtensionType`.
struct {
ExtensionType extensionType;
opaque extensionData<0..65535>;
} Extension;
struct {
SerializationVersion version;
ATLeafType type;
opaque description<0..255>;
HashValue dataHash;
uint64 expiryMs;
Extension extensions<0..65535>;
} ATLeafData
enum {
V1(1);
(255)
} SerializationVersion;
enum {
RELEASE(1);
KEYBUNDLE_TGT(3);
KEYBUNDLE_OTT(4);
KEYBUNDLE_OHTTP(5);
TEST_MARKER(100);
(255)
} ATLeafType;Log integrity verification
We constructed PCC’s transparency log by using Merkle trees, similar to Certificate Transparency. PCC employs three types of trees:
Application Tree: Each leaf is the SHA-256 digest of a binary-encoded Release data structure.
Per-Application Tree: Each leaf contains the
LogHeadof each revision of the Application Tree.Top-Level Tree: Leaves contain the Merkle tree root hash of every revision of the Per-Application Tree, as well as those for applications unrelated to PCC, meaning not every leaf is relevant to PCC.
In a valid transparency log, each of the following invariants holds:
Every revision of a tree represents an append-only extension of the previous revision’s leaves.
For each revision of the Application Tree, the root hash is a leaf in the Per-Application Tree.
For each revision of the Per-Application Tree, the root hash is a leaf in the Top-Level Tree.
You can verify the integrity of the transparency log by using the auditor APIs to download all known leaves of each level of tree, bottom to top starting from the Application Tree, and confirming the consistency of the tree as follows:
Within every leaf in the Top-Level Tree with the application identifier
PRIVATE_CLOUD_COMPUTE (5)is aLogHeadobject that describes the tree shape and root hash of a particular revision of a Per-Application Tree. Reconstructing a Merkle Tree using all Per-Application Tree leaves from the range(0..<LogHead.logSize)must result in a SHA256 digest equal toLogHead.logHeadHash.You can apply this same verification process to the Per-Application Tree, where each leaf is a
LogHeadrepresenting a revision of the Application Tree.
The PCC Virtual Research Environment comes with a reference implementation that you can use to audit the correctness of the transparency log. For more information about using the VRE tooling for this purpose, see Auditing the transparency log.