roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/server.h (about) 1 /* Copyright 2016 The Roughtime Authors. 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. */ 14 15 #ifndef SECURITY_ROUGHTIME_SERVER_H_ 16 #define SECURITY_ROUGHTIME_SERVER_H_ 17 18 #include <memory> 19 #include <utility> 20 21 #include "protocol.h" 22 #include "time_source.h" 23 24 namespace roughtime { 25 26 // kToBeSignedCertSize is the size of the signed portion (DELE) of a 27 // certificate. Its tags are (PUBK, MINT, MAXT). 28 constexpr size_t kToBeSignedCertSize = MessageHeaderLen(3) + 29 kPublicKeyLength + kTimestampSize + 30 kTimestampSize; 31 32 // kCertSize is the size of the entire certificate. Its tags are (DELE, SIG). 33 constexpr size_t kCertSize = 34 MessageHeaderLen(2) + kSignatureLength + kToBeSignedCertSize; 35 36 // CreateCertificate signs the supplied |public_key| using |root_private_key|, 37 // and sets |out_cert| to a certificate containing the public key, the 38 // signature, and the supplied validity interval. Returns true if successful, 39 // otherwise false. 40 // TODO(mab): Find better home for this, likely in an offline tool. 41 bool CreateCertificate(uint8_t out_cert[kCertSize], 42 const uint8_t root_private_key[kPrivateKeyLength], 43 rough_time_t start_time, rough_time_t end_time, 44 const uint8_t public_key[kPublicKeyLength]); 45 46 // Identity is a server's private key and certificate. (The certificate is the 47 // server's public key signed by an offline private master key.) 48 struct Identity { 49 uint8_t private_key[kPrivateKeyLength]; 50 uint8_t certificate[kCertSize]; 51 }; 52 53 // kBatchSizeLog2 is one less than the number of levels in the Merkle tree of 54 // client nonces. The response packet must have room for this many hashes. 55 // This value was taken because it's too easy to saturate batches of size 32 in 56 // load testing so 64 seems like a reasonable number for now. We may revisit 57 // this if the non-crypto parts of processing become less expensive. 58 constexpr size_t kBatchSizeLog2 = 6; 59 60 // kBatchSize is the most requests we'll process at a time, a.k.a. the number of 61 // leaves in the Merkle tree. 62 constexpr size_t kBatchSize = 1 << kBatchSizeLog2; 63 64 // Tree encapsulates the Merkle tree of client nonces. The tree is too large 65 // (2**13 bytes) to be sent to each client, so each client is sent the part of 66 // the tree necessary to verify the inclusion of its nonce. 67 class Tree { 68 public: 69 Tree() {} 70 Tree(const Tree&) = delete; 71 Tree& operator=(const Tree&) = delete; 72 73 // AddLeaf adds a new client nonce at the specified index. 74 void AddLeaf(size_t index, const uint8_t nonce[kNonceLength]) { 75 HashLeaf(tree_[0][index], nonce); 76 } 77 78 // Build constructs the Merkle tree. The existing |num_leaves| leaf hashes in 79 // levels_[0] are left alone, and the tree is built by (possibly adding a 80 // dummy leaf node and) creating levels 1 and higher. 81 // 82 // If |num_leaves| is 1, this is a no-op. In that case, the root is the same 83 // node as the one leaf. 84 void Build(size_t num_leaves); 85 86 // GetPathLength returns the number of nodes necessary to represent a path to 87 // the root. This may be zero. 88 size_t GetPathLength() { return levels_ - 1; } 89 90 // GetPath sets |*out_path| to the data needed to verify inclusion in the root 91 // hash of the leaf at |index|. The path consists of one node for each 92 // sub-root level. So, for example, the first element is the leaf that is the 93 // sibling of the leaf at |index|. 94 // 95 // The data are intended for consumption by a client that knows the leaf at 96 // |index|, because it is that client's nonce. 97 void GetPath(uint8_t* out_path, size_t index); 98 99 // GetRoot returns a pointer to the root hash, which is |kNonceLength| bytes 100 // long. 101 const uint8_t* GetRoot() { return tree_[levels_ - 1][0]; } 102 103 private: 104 // tree_ is a Merkle tree. The first index is the level of the tree, with 105 // leaves at level 0. 106 uint8_t tree_[kBatchSizeLog2 + 1][kBatchSize][kNonceLength]; 107 108 // Level is the number of levels in the tree, including the root. Hence, 109 // after calling |Build|, the root lives at |tree_[levels_-1][0]|. 110 size_t levels_; 111 }; 112 113 constexpr size_t kMaxRecvPacketSize = kMinRequestSize; 114 115 constexpr size_t kToBeSignedSize = 116 MessageHeaderLen(3) + kTimestampSize + kRadiusSize + kNonceLength; 117 118 // kMaxResponseSize is the size of the largest possible server response. 119 constexpr size_t kMaxResponseSize = 120 MessageHeaderLen(5) + kCertSize + kToBeSignedSize + kSignatureLength + 121 (kBatchSizeLog2 * kNonceLength) + sizeof(uint32_t) /* index */; 122 123 class Server { 124 public: 125 Server() = delete; 126 Server(const Server&) = delete; 127 Server& operator=(const Server&) = delete; 128 129 Server(std::unique_ptr<Identity> identity, 130 std::unique_ptr<TimeSource> time_source); 131 132 // AddRequest decodes |packet|. If the packet is valid, it is added to 133 // |tree_| and true is returned. Otherwise, false is returned. 134 bool AddRequest(const uint8_t* packet, size_t len); 135 136 // Sign creates a signed response (Merkle tree root and timestamp) and a 137 // signature. 138 bool Sign(); 139 140 // MakeResponse creates a response for the |index|'th leaf node of the Merkle 141 // tree, where the indices correspond to successful calls to |AddRequest|. 142 bool MakeResponse(uint8_t* out_response, size_t* out_len, uint32_t index); 143 144 void Reset() { num_leaves_ = 0; } 145 146 private: 147 std::unique_ptr<TimeSource> time_source_; 148 149 std::unique_ptr<Identity> identity_; 150 151 Tree tree_; 152 // num_leaves is the number of leaf nodes inserted 153 size_t num_leaves_; 154 155 // to_be_signed_with_context_ is the signed portion of the server's response, 156 // prefixed by |kContextString|. 157 uint8_t to_be_signed_with_context_[kToBeSignedSize + sizeof(kContextString)]; 158 159 // to_be_signed_ points |sizeof(kContextStringBytes)| into 160 // |to_be_signed_with_context_|, for convenience. It contains tags (ROOT, 161 // TIME). 162 uint8_t* const to_be_signed_; 163 164 // Signature is the ED25519 signature over |to_be_signed_with_context_|. 165 uint8_t signature_[kSignatureLength]; 166 }; 167 168 // BrokenReplyGenerator is an interface for generating replies that are broken 169 // in a variety of ways. This is used to ensure that clients correctly handle 170 // various corner cases. 171 class BrokenReplyGenerator { 172 public: 173 virtual ~BrokenReplyGenerator(); 174 175 // probability_1024 returns the probability, in parts-per-1024, that this 176 // generator should be used for a given request. 177 uint16_t probability_1024() const; 178 void set_probability_1024(uint16_t probabilty); 179 180 // Process takes a valid request in |request| and the standard response in 181 // |normal_response|. If it wishes to substitute an alternative reply then it 182 // may write up to |max_out_len| bytes to |out|, set |*out_len| to the number 183 // of bytes written and return true. Otherwise it must return false. 184 virtual bool Process(uint8_t* out, size_t* out_len, size_t max_out_len, 185 const uint8_t* normal_response, 186 size_t normal_response_len, const uint8_t* request, 187 size_t request_len) = 0; 188 189 protected: 190 uint16_t probability_1024_ = 0; 191 }; 192 193 } // namespace roughtime 194 195 #endif // SECURITY_ROUGHTIME_SERVER_H_