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