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_