roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/server.cc (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 #include <errno.h> 16 #include <stdint.h> 17 #include <string.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 21 #include <openssl/curve25519.h> 22 23 #include "logging.h" 24 #include "protocol.h" 25 #include "server.h" 26 27 namespace roughtime { 28 29 static_assert(kMaxRecvPacketSize % 4 == 0, 30 "kMaxRecvPacketSize must be a multiple of four"); 31 static_assert(kBatchSize != 0 && (kBatchSize & (kBatchSize - 1)) == 0, 32 "kBatchSize must be a power of two"); 33 static_assert(1u << kBatchSizeLog2 == kBatchSize, 34 "kBatchSizeLog2 is incorrect"); 35 static_assert(kMinRequestSize <= kMaxRecvPacketSize, 36 "Miniumum request size must be <= to the maximum packet size"); 37 38 static_assert(kMaxResponseSize <= kMinRequestSize, 39 "This design could be a DDoS amplifier"); 40 41 static_assert(ED25519_SIGNATURE_LEN == 64, "crypto constant mismatch"); 42 static_assert(ED25519_PUBLIC_KEY_LEN == 32, "crypto constant mismatch"); 43 static_assert(ED25519_PRIVATE_KEY_LEN == 64, "crypto constant mismatch"); 44 45 Server::Server(std::unique_ptr<Identity> identity, 46 std::unique_ptr<TimeSource> time_source) 47 : time_source_(std::move(time_source)), 48 identity_(std::move(identity)), 49 num_leaves_(0), 50 to_be_signed_(to_be_signed_with_context_ + sizeof(kContextString)) { 51 memcpy(to_be_signed_with_context_, kContextString, sizeof(kContextString)); 52 } 53 54 bool Server::AddRequest(const uint8_t *packet, size_t len) { 55 ROUGHTIME_DCHECK_LE(num_leaves_, kBatchSize); 56 57 if (len < kMinRequestSize) { 58 return false; 59 } 60 61 Parser request(packet, len); 62 if (!request.is_valid()) { 63 return false; 64 } 65 66 const uint8_t *nonce; 67 if (!request.GetFixedLen(&nonce, kTagNONC, kNonceLength)) { 68 return false; 69 } 70 71 // kTagPAD lives here too, but we don't bother to check for it. The check 72 // above against |kMinRequestSize| is sufficient. 73 tree_.AddLeaf(num_leaves_++, nonce); 74 75 return true; 76 } 77 78 bool Server::Sign() { 79 ROUGHTIME_DCHECK_GT(num_leaves_, 0ul); 80 81 // The signature is over the root hash and the timestamp---that's it! 82 tree_.Build(num_leaves_); 83 const auto interval = time_source_->Now(); 84 const rough_time_t now = interval.first; 85 const uint32_t radius = interval.second; 86 87 Builder to_be_signed(to_be_signed_, kToBeSignedSize, 3); 88 size_t to_be_signed_len; 89 90 static_assert(kTagRADI < kTagMIDP, "Tags must be written in order"); 91 static_assert(kTagMIDP < kTagROOT, "Tags must be written in order"); 92 if (!to_be_signed.AddTagData(kTagRADI, 93 reinterpret_cast<const uint8_t *>(&radius), 94 sizeof(radius)) || 95 !to_be_signed.AddTagData( 96 kTagMIDP, reinterpret_cast<const uint8_t *>(&now), sizeof(now)) || 97 !to_be_signed.AddTagData(kTagROOT, tree_.GetRoot(), kNonceLength) || 98 !to_be_signed.Finish(&to_be_signed_len)) { 99 ROUGHTIME_LOG(ERROR) << "failed to construct to_be_signed"; 100 return false; 101 } 102 ROUGHTIME_CHECK_EQ(to_be_signed_len, kToBeSignedSize); 103 104 if (!ED25519_sign(signature_, to_be_signed_with_context_, 105 sizeof(to_be_signed_with_context_), 106 identity_->private_key)) { 107 ROUGHTIME_LOG(ERROR) << "signature failure"; 108 return false; 109 } 110 return true; 111 } 112 113 bool Server::MakeResponse(uint8_t *out_response, size_t *out_len, 114 uint32_t index) { 115 ROUGHTIME_DCHECK_LT(index, num_leaves_); 116 static_assert(kMaxResponseSize <= kMaxRecvPacketSize, 117 "Receive buffers are too small to use as send buffers"); 118 Builder response(out_response, kMaxResponseSize, 5); 119 static_assert(kTagSIG < kTagPATH, "Tags must be written in order"); 120 static_assert(kTagPATH < kTagSREP, "Tags must be written in order"); 121 static_assert(kTagSREP < kTagCERT, "Tags must be written in order"); 122 static_assert(kTagCERT < kTagINDX, "Tags must be written in order"); 123 124 uint8_t *path; 125 uint8_t *pindex = reinterpret_cast<uint8_t *>(&index); 126 if (!response.AddTagData(kTagSIG, signature_, sizeof(signature_)) || 127 !response.AddTag(&path, kTagPATH, kNonceLength * tree_.GetPathLength()) || 128 !response.AddTagData(kTagSREP, to_be_signed_, kToBeSignedSize) || 129 !response.AddTagData(kTagCERT, identity_->certificate, kCertSize) || 130 !response.AddTagData(kTagINDX, pindex, sizeof(index)) || 131 !response.Finish(out_len)) { 132 ROUGHTIME_LOG(ERROR) << "failed to construct response"; 133 return false; 134 } 135 136 tree_.GetPath(path, index); 137 return true; 138 } 139 140 // static 141 bool CreateCertificate(uint8_t out_cert[kCertSize], 142 const uint8_t root_private_key[ED25519_PRIVATE_KEY_LEN], 143 rough_time_t start_time, rough_time_t end_time, 144 const uint8_t public_key[ED25519_PUBLIC_KEY_LEN]) { 145 ROUGHTIME_CHECK_LT(start_time, end_time); 146 uint8_t to_be_signed_bytes[sizeof(kCertContextString) + kToBeSignedCertSize]; 147 size_t to_be_signed_len; 148 memcpy(to_be_signed_bytes, kCertContextString, sizeof(kCertContextString)); 149 150 Builder to_be_signed(to_be_signed_bytes + sizeof(kCertContextString), 151 kToBeSignedCertSize, 3); 152 static_assert(kTagPUBK < kTagMINT, "Tags must be written in order"); 153 static_assert(kTagMINT < kTagMAXT, "Tags must be written in order"); 154 if (!to_be_signed.AddTagData(kTagPUBK, public_key, ED25519_PUBLIC_KEY_LEN) || 155 !to_be_signed.AddTagData(kTagMINT, 156 reinterpret_cast<uint8_t *>(&start_time), 157 sizeof(start_time)) || 158 !to_be_signed.AddTagData(kTagMAXT, reinterpret_cast<uint8_t *>(&end_time), 159 sizeof(end_time)) || 160 !to_be_signed.Finish(&to_be_signed_len)) { 161 ROUGHTIME_LOG(ERROR) << "failed to construct signed portion of certificate"; 162 return false; 163 } 164 ROUGHTIME_CHECK_EQ(to_be_signed_len, kToBeSignedCertSize); 165 166 uint8_t signature[ED25519_SIGNATURE_LEN]; 167 if (!ED25519_sign(signature, to_be_signed_bytes, sizeof(to_be_signed_bytes), 168 root_private_key)) { 169 ROUGHTIME_LOG(ERROR) << "failed to sign certificate"; 170 return false; 171 } 172 173 size_t cert_len; 174 Builder cert(out_cert, kCertSize, 2); 175 176 static_assert(kTagSIG < kTagDELE, "Tags must be written in order"); 177 if (!cert.AddTagData(kTagSIG, signature, sizeof(signature)) || 178 !cert.AddTagData(kTagDELE, 179 to_be_signed_bytes + sizeof(kCertContextString), 180 to_be_signed_len) || 181 !cert.Finish(&cert_len)) { 182 ROUGHTIME_LOG(ERROR) << "failed to construct certificate"; 183 return false; 184 } 185 ROUGHTIME_CHECK_EQ(cert_len, kCertSize); 186 return true; 187 } 188 189 void Tree::Build(size_t num_nodes) { 190 ROUGHTIME_DCHECK_GT(num_nodes, 0ul); 191 size_t level; 192 for (level = 0; num_nodes > 1; level++, num_nodes /= 2) { 193 // Even out the level with a dummy node, if need be. Use an existing node 194 // in |tree_|, to simplify analysis that we are not inadvertently signing 195 // other messages. 196 if (num_nodes % 2 == 1) { 197 memcpy(tree_[level][num_nodes], tree_[level][0], kNonceLength); 198 num_nodes++; 199 } 200 for (size_t i = 0; i < num_nodes; i += 2) { 201 HashNode(tree_[level + 1][i / 2], tree_[level][i], tree_[level][i + 1]); 202 } 203 } 204 ROUGHTIME_DCHECK_EQ(1ul, num_nodes); // Root node. 205 levels_ = level + 1; 206 } 207 208 void Tree::GetPath(uint8_t *out_path, size_t index) { 209 // At the lowest level, the client knows its own leaf hash, so send it only 210 // that leaf's sibling, and so on up the tree. 211 for (size_t level = 0; level < levels_ - 1; level++) { 212 if (index % 2 == 1) { 213 memcpy(out_path, tree_[level][index - 1], kNonceLength); 214 } else { 215 memcpy(out_path, tree_[level][index + 1], kNonceLength); 216 } 217 out_path += kNonceLength; 218 index /= 2; 219 } 220 ROUGHTIME_DCHECK_EQ(0ul, index); 221 } 222 223 BrokenReplyGenerator::~BrokenReplyGenerator() {} 224 225 uint16_t BrokenReplyGenerator::probability_1024() const { 226 return probability_1024_; 227 } 228 229 void BrokenReplyGenerator::set_probability_1024(uint16_t probability) { 230 probability_1024_ = probability; 231 } 232 233 } // namespace roughtime