roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/protocol.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_PROTOCOL_H_
    16  #define SECURITY_ROUGHTIME_PROTOCOL_H_
    17  
    18  #include <stdint.h>
    19  #include <string.h>
    20  
    21  namespace roughtime {
    22  
    23  // Minimum size of a time request.  Requests must be padded to larger than their
    24  // contents in order to reduce the value of a time server as a DDOS amplifier.
    25  constexpr size_t kMinRequestSize = 1024;
    26  
    27  constexpr size_t kNonceLength = 64;  // Size of the client's nonce.
    28  
    29  constexpr size_t kTimestampSize = 8;  // Size of the server's time.
    30  
    31  constexpr size_t kRadiusSize = 4;  // Size of the server's uncertainty.
    32  
    33  constexpr size_t kPrivateKeyLength = 64; // Size of the server's private key.
    34  
    35  constexpr size_t kPublicKeyLength = 32; // Size of the server's public key.
    36  
    37  constexpr size_t kSignatureLength = 64; // Size of server signatures.
    38  
    39  typedef uint32_t tag_t;
    40  
    41  // rough_time_t is the type of a time stamp. Time is UTC and is given as
    42  // milliseconds since the UNIX epoch (00:00:00 UTC on 1 January 1970). Leap
    43  // seconds are linearly smeared over a 24-hour period. That is, the smear
    44  // extends from UTC noon to noon over 86,401 or 86,399 SI seconds, and all the
    45  // smeared seconds are the same length.
    46  typedef uint64_t rough_time_t;
    47  
    48  // MakeTag creates an integer value representing a tag.  Requests and responses
    49  // in the time protocol are made up of tagged data, QUIC-style.  Tags are 4
    50  // bytes long and meant to be readable-ish, but they cannot be chosen with
    51  // complete freedom, because they must be strictly increasing within a message
    52  // to permit binary searches.
    53  constexpr tag_t MakeTag(char a, char b, char c, char d) {
    54    return static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
    55           static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
    56  }
    57  
    58  // kTagNONC ("nonce") is used in client requests.  It tags the request's nonce.
    59  constexpr tag_t kTagNONC = MakeTag('N', 'O', 'N', 'C');
    60  // kTagPAD ("padding") is used in client requests.  It tags the padding that
    61  // fills out the request to at least |kMinRequestSize|.
    62  constexpr tag_t kTagPAD = MakeTag('P', 'A', 'D', '\xff');
    63  
    64  // kTagMIDP is used in the signed portion of server responses.  It tags the
    65  // midpoint of the server's time in Unix epoch-microseconds.
    66  constexpr tag_t kTagMIDP = MakeTag('M', 'I', 'D', 'P');
    67  // kTagRADI contains the radius of uncertainty (in microseconds) of the
    68  // server's time.
    69  constexpr tag_t kTagRADI = MakeTag('R', 'A', 'D', 'I');
    70  // kTagROOT is used in the signed portion of server responses.  It tags the root
    71  // of a Merkle tree that contains the nonces from a batch of client requests.
    72  constexpr tag_t kTagROOT = MakeTag('R', 'O', 'O', 'T');
    73  
    74  // kTagSIG ("signature") is used in in the unsigned portion of server responses.
    75  // It tags a signature made using the key from the server's certificate.
    76  constexpr tag_t kTagSIG = MakeTag('S', 'I', 'G', '\0');
    77  // kTagPATH is used in the unsigned portion of server responses.  It tags the
    78  // path from the client's nonce, a leaf node, to the root of the Merkle tree, so
    79  // that the client can verify the inclusion of its nonce in the tree.
    80  constexpr tag_t kTagPATH = MakeTag('P', 'A', 'T', 'H');
    81  // kTagSREP ("signed response") is used in the unsigned portion
    82  // of server responses.  It tags the signed portion of the response.
    83  constexpr tag_t kTagSREP = MakeTag('S', 'R', 'E', 'P');
    84  // kTagCERT ("certificate") is used in the unsigned portion of server responses.
    85  // It tags a (not X.509) certificate.  The tagged value is the public key whose
    86  // private key the server uses to sign its response.  The public key is signed
    87  // offline by another keypair, whose public key is baked into the client.
    88  constexpr tag_t kTagCERT = MakeTag('C', 'E', 'R', 'T');
    89  // kTagINDX ("index") is used in the unsigned portion of server responses.  It
    90  // tells the client the index that was assigned to its nonce when generating the
    91  // Merkle tree.
    92  constexpr tag_t kTagINDX = MakeTag('I', 'N', 'D', 'X');
    93  
    94  // kTagPUBK ("public key") is used in server certificates.  It tags the public
    95  // key whose private key was used to sign the server's response.
    96  constexpr tag_t kTagPUBK = MakeTag('P', 'U', 'B', 'K');
    97  // kTagMINT ("minimum validity timestamp") is used in server certificates.  It
    98  // tags the beginning of the certificate's validity period.
    99  constexpr tag_t kTagMINT = MakeTag('M', 'I', 'N', 'T');
   100  // kTagMAXT ("maximum validity timestamp") is used in server certificates.  It
   101  // tags the end of the certificate's validity period.
   102  constexpr tag_t kTagMAXT = MakeTag('M', 'A', 'X', 'T');
   103  // kTagDELE ("delegation") is used in server certificates.  It tags the data
   104  // signed by the server's offline key.
   105  constexpr tag_t kTagDELE = MakeTag('D', 'E', 'L', 'E');
   106  
   107  // kContextString is prefixed to the server's response before generating or
   108  // verifying the server's signature.
   109  static const char kContextString[] = "RoughTime v1 response signature";
   110  static_assert(sizeof(kContextString) % 4 == 0,
   111                "Context strings must be a multiple of four bytes long");
   112  
   113  // kCertContextString is added as a prefix to the server's certificate before
   114  // generating or verifying the certificate's signature.
   115  static const char kCertContextString[] = "RoughTime v1 delegation signature--";
   116  static_assert(sizeof(kCertContextString) % 4 == 0,
   117                "Context strings must be a multiple of four bytes long");
   118  
   119  // NumMessageOffsets gives the size in entries of the table of offsets for a
   120  // time protocol message having |num_tags| tags.  (Since the length of messages
   121  // in the time protocol is known, a message with only one tag does not need a
   122  // table of offsets.)
   123  constexpr size_t NumMessageOffsets(size_t num_tags) {
   124    return num_tags == 0 ? 0 : num_tags - 1;
   125  }
   126  
   127  // MessageHeaderLen gives the size in bytes of a message header, which consists
   128  // of a tag count, a table of offsets (if there are least two tags), and a list
   129  // of 0 or more tags.
   130  constexpr size_t MessageHeaderLen(size_t num_tags) {
   131    return sizeof(uint32_t) /* tag count */ +
   132           sizeof(uint32_t) * NumMessageOffsets(num_tags) /* offsets */ +
   133           sizeof(tag_t) * num_tags /* tag values */;
   134  }
   135  
   136  // kPaddingLen is the number of padding bytes necessary to make a client request
   137  // sufficiently long.
   138  constexpr size_t kPaddingLen =
   139      kMinRequestSize - (MessageHeaderLen(2) + kNonceLength);
   140  
   141  // Parser decodes requests from a time server client.
   142  //
   143  //  0                   1                   2                   3
   144  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   145  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   146  // |                         Number of tags                        |
   147  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   148  // |                       Offset, Tag 1 Data                      |
   149  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   150  // |                              ...                              |
   151  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   152  // |                       Offset, Tag N Data                      |
   153  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   154  // |                             Tag 0                             |
   155  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   156  // |                              ...                              |
   157  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   158  // |                             Tag N                             |
   159  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   160  // |                             Data...                           |
   161  // |                      (indexed by offsets)                     |
   162  // |                                                               |
   163  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   164  class Parser {
   165   public:
   166    // Parses the supplied data.  No copies are made, so the data pointed to by
   167    // |req| must live as long as the |Parser| object.  Callers should check
   168    // |is_valid| before calling any other method.
   169    Parser(const uint8_t* req, size_t len);
   170  
   171    Parser() = delete;
   172    Parser(const Parser&) = delete;
   173    Parser& operator=(const Parser&) = delete;
   174  
   175    bool is_valid() const { return is_valid_; }
   176  
   177    // GetTag sets |*out_data| and |*out_len| to reflect the location (within the
   178    // data supplied to the constructor) of the tag |tag|, if found.  Returns true
   179    // if |tag| is found.
   180    bool GetTag(const uint8_t** out_data, size_t* out_len, tag_t tag) const;
   181  
   182    // GetFixedLen is a specialization of |GetTag| that returns true only if the
   183    // data tagged by |tag| is |expected_len| bytes long.
   184    bool GetFixedLen(const uint8_t** out_data, tag_t tag,
   185                     size_t expected_len) const;
   186  
   187    // Get is a specialization of |GetFixedLen| that expects |tag| to tag a value
   188    // of type |T|.  The tagged value is assigned to |*out_value|.
   189    template <typename T>
   190    bool Get(T* out_value, tag_t tag) const;
   191  
   192   private:
   193    bool is_valid_ = false;
   194    size_t num_tags_;
   195    const uint8_t* offsets_;  // |NumMessageOffsets| offsets into |data_|.
   196    const uint8_t* tags_;        // |num_tags_| 32-bit tags.
   197    const uint8_t* data_;      // |len_| bytes.
   198    size_t len_;
   199  };
   200  
   201  // Builder creates a time server response.
   202  class Builder {
   203   public:
   204    Builder() = delete;
   205    Builder(const Builder&) = delete;
   206    Builder& operator=(const Builder&) = delete;
   207  
   208    // Prepares to write tags and data to a buffer |out| of |out_len| bytes.
   209    Builder(uint8_t* out, size_t out_len, size_t num_tags);
   210  
   211    // AddTag adds the tag |tag| to the response, which must be greater than any
   212    // previously added tag, and sets |*out_data| to an address where |len| bytes
   213    // may be written.  Returns true iff the tag may be written.
   214    bool AddTag(uint8_t** out_data, tag_t tag, size_t len);
   215  
   216    // AddTagData is a specialization of |AddTag| that copies the |len| bytes
   217    // pointed to by |data| into the response.  Returns true iff the tag was
   218    // written.
   219    bool AddTagData(tag_t tag, const uint8_t* data, size_t len);
   220  
   221    // Finish returns true if the response is valid, and sets |out_len| to the
   222    // size of the response.  After calling |Finish| all subsequent calls will
   223    // fail.
   224    bool Finish(size_t* out_len);
   225  
   226   private:
   227    const size_t num_tags_;
   228    const size_t header_len_;
   229    uint8_t* const offsets_;
   230    uint8_t* const tags_;
   231  
   232    uint8_t* data_;      // Offset of next |AddTag|.
   233    size_t len_;         // Bytes remaining in the output buffer.
   234    size_t offset_ = 0;  // Offset of data for next tag.
   235  
   236    size_t tag_i_ = 0;  // Index of next tag.
   237    tag_t previous_tag_;
   238    bool have_previous_tag_ = false;
   239  
   240    bool valid_ = false;
   241  };
   242  
   243  // Computes the SHA-512 hash of a Merkle tree leaf, i.e. a client's nonce, as
   244  // 0||nonce.  |in| is assumed to point to |kNonceLength| bytes and |out| is
   245  // assumed to have space for |SHA512_DIGEST_LENGTH| bytes.
   246  void HashLeaf(uint8_t* out, const uint8_t* in);
   247  
   248  // Computes the SHA-512 hash of a Merkle tree node as 1||left||right.  |left|,
   249  // |right|, and |out| are assumed to point to |SHA512_DIGEST_LENGTH| bytes.
   250  void HashNode(uint8_t* out, const uint8_t* left, const uint8_t* right);
   251  
   252  }  // namespace roughtime
   253  
   254  #endif  // SECURITY_ROUGHTIME_PROTOCOL_H_