| /* Copyright 2016 The Roughtime Authors. | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *   http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. */ | 
 |  | 
 | #ifndef SECURITY_ROUGHTIME_PROTOCOL_H_ | 
 | #define SECURITY_ROUGHTIME_PROTOCOL_H_ | 
 |  | 
 | #include <stdint.h> | 
 | #include <string.h> | 
 |  | 
 | namespace roughtime { | 
 |  | 
 | // Minimum size of a time request.  Requests must be padded to larger than their | 
 | // contents in order to reduce the value of a time server as a DDOS amplifier. | 
 | constexpr size_t kMinRequestSize = 1024; | 
 |  | 
 | constexpr size_t kNonceLength = 64;  // Size of the client's nonce. | 
 |  | 
 | constexpr size_t kTimestampSize = 8;  // Size of the server's time. | 
 |  | 
 | constexpr size_t kRadiusSize = 4;  // Size of the server's uncertainty. | 
 |  | 
 | constexpr size_t kPrivateKeyLength = 64; // Size of the server's private key. | 
 |  | 
 | constexpr size_t kPublicKeyLength = 32; // Size of the server's public key. | 
 |  | 
 | constexpr size_t kSignatureLength = 64; // Size of server signatures. | 
 |  | 
 | typedef uint32_t tag_t; | 
 |  | 
 | // rough_time_t is the type of a time stamp. Time is UTC and is given as | 
 | // milliseconds since the UNIX epoch (00:00:00 UTC on 1 January 1970). Leap | 
 | // seconds are linearly smeared over a 24-hour period. That is, the smear | 
 | // extends from UTC noon to noon over 86,401 or 86,399 SI seconds, and all the | 
 | // smeared seconds are the same length. | 
 | typedef uint64_t rough_time_t; | 
 |  | 
 | // MakeTag creates an integer value representing a tag.  Requests and responses | 
 | // in the time protocol are made up of tagged data, QUIC-style.  Tags are 4 | 
 | // bytes long and meant to be readable-ish, but they cannot be chosen with | 
 | // complete freedom, because they must be strictly increasing within a message | 
 | // to permit binary searches. | 
 | constexpr tag_t MakeTag(char a, char b, char c, char d) { | 
 |   return static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 | | 
 |          static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24; | 
 | } | 
 |  | 
 | // kTagNONC ("nonce") is used in client requests.  It tags the request's nonce. | 
 | constexpr tag_t kTagNONC = MakeTag('N', 'O', 'N', 'C'); | 
 | // kTagPAD ("padding") is used in client requests.  It tags the padding that | 
 | // fills out the request to at least |kMinRequestSize|. | 
 | constexpr tag_t kTagPAD = MakeTag('P', 'A', 'D', '\xff'); | 
 |  | 
 | // kTagMIDP is used in the signed portion of server responses.  It tags the | 
 | // midpoint of the server's time in Unix epoch-microseconds. | 
 | constexpr tag_t kTagMIDP = MakeTag('M', 'I', 'D', 'P'); | 
 | // kTagRADI contains the radius of uncertainty (in microseconds) of the | 
 | // server's time. | 
 | constexpr tag_t kTagRADI = MakeTag('R', 'A', 'D', 'I'); | 
 | // kTagROOT is used in the signed portion of server responses.  It tags the root | 
 | // of a Merkle tree that contains the nonces from a batch of client requests. | 
 | constexpr tag_t kTagROOT = MakeTag('R', 'O', 'O', 'T'); | 
 |  | 
 | // kTagSIG ("signature") is used in in the unsigned portion of server responses. | 
 | // It tags a signature made using the key from the server's certificate. | 
 | constexpr tag_t kTagSIG = MakeTag('S', 'I', 'G', '\0'); | 
 | // kTagPATH is used in the unsigned portion of server responses.  It tags the | 
 | // path from the client's nonce, a leaf node, to the root of the Merkle tree, so | 
 | // that the client can verify the inclusion of its nonce in the tree. | 
 | constexpr tag_t kTagPATH = MakeTag('P', 'A', 'T', 'H'); | 
 | // kTagSREP ("signed response") is used in the unsigned portion | 
 | // of server responses.  It tags the signed portion of the response. | 
 | constexpr tag_t kTagSREP = MakeTag('S', 'R', 'E', 'P'); | 
 | // kTagCERT ("certificate") is used in the unsigned portion of server responses. | 
 | // It tags a (not X.509) certificate.  The tagged value is the public key whose | 
 | // private key the server uses to sign its response.  The public key is signed | 
 | // offline by another keypair, whose public key is baked into the client. | 
 | constexpr tag_t kTagCERT = MakeTag('C', 'E', 'R', 'T'); | 
 | // kTagINDX ("index") is used in the unsigned portion of server responses.  It | 
 | // tells the client the index that was assigned to its nonce when generating the | 
 | // Merkle tree. | 
 | constexpr tag_t kTagINDX = MakeTag('I', 'N', 'D', 'X'); | 
 |  | 
 | // kTagPUBK ("public key") is used in server certificates.  It tags the public | 
 | // key whose private key was used to sign the server's response. | 
 | constexpr tag_t kTagPUBK = MakeTag('P', 'U', 'B', 'K'); | 
 | // kTagMINT ("minimum validity timestamp") is used in server certificates.  It | 
 | // tags the beginning of the certificate's validity period. | 
 | constexpr tag_t kTagMINT = MakeTag('M', 'I', 'N', 'T'); | 
 | // kTagMAXT ("maximum validity timestamp") is used in server certificates.  It | 
 | // tags the end of the certificate's validity period. | 
 | constexpr tag_t kTagMAXT = MakeTag('M', 'A', 'X', 'T'); | 
 | // kTagDELE ("delegation") is used in server certificates.  It tags the data | 
 | // signed by the server's offline key. | 
 | constexpr tag_t kTagDELE = MakeTag('D', 'E', 'L', 'E'); | 
 |  | 
 | // kContextString is prefixed to the server's response before generating or | 
 | // verifying the server's signature. | 
 | static const char kContextString[] = "RoughTime v1 response signature"; | 
 | static_assert(sizeof(kContextString) % 4 == 0, | 
 |               "Context strings must be a multiple of four bytes long"); | 
 |  | 
 | // kCertContextString is added as a prefix to the server's certificate before | 
 | // generating or verifying the certificate's signature. | 
 | static const char kCertContextString[] = "RoughTime v1 delegation signature--"; | 
 | static_assert(sizeof(kCertContextString) % 4 == 0, | 
 |               "Context strings must be a multiple of four bytes long"); | 
 |  | 
 | // NumMessageOffsets gives the size in entries of the table of offsets for a | 
 | // time protocol message having |num_tags| tags.  (Since the length of messages | 
 | // in the time protocol is known, a message with only one tag does not need a | 
 | // table of offsets.) | 
 | constexpr size_t NumMessageOffsets(size_t num_tags) { | 
 |   return num_tags == 0 ? 0 : num_tags - 1; | 
 | } | 
 |  | 
 | // MessageHeaderLen gives the size in bytes of a message header, which consists | 
 | // of a tag count, a table of offsets (if there are least two tags), and a list | 
 | // of 0 or more tags. | 
 | constexpr size_t MessageHeaderLen(size_t num_tags) { | 
 |   return sizeof(uint32_t) /* tag count */ + | 
 |          sizeof(uint32_t) * NumMessageOffsets(num_tags) /* offsets */ + | 
 |          sizeof(tag_t) * num_tags /* tag values */; | 
 | } | 
 |  | 
 | // kPaddingLen is the number of padding bytes necessary to make a client request | 
 | // sufficiently long. | 
 | constexpr size_t kPaddingLen = | 
 |     kMinRequestSize - (MessageHeaderLen(2) + kNonceLength); | 
 |  | 
 | // Parser decodes requests from a time server client. | 
 | // | 
 | //  0                   1                   2                   3 | 
 | //  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 | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                         Number of tags                        | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                       Offset, Tag 1 Data                      | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                              ...                              | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                       Offset, Tag N Data                      | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                             Tag 0                             | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                              ...                              | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                             Tag N                             | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | // |                             Data...                           | | 
 | // |                      (indexed by offsets)                     | | 
 | // |                                                               | | 
 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
 | class Parser { | 
 |  public: | 
 |   // Parses the supplied data.  No copies are made, so the data pointed to by | 
 |   // |req| must live as long as the |Parser| object.  Callers should check | 
 |   // |is_valid| before calling any other method. | 
 |   Parser(const uint8_t* req, size_t len); | 
 |  | 
 |   Parser() = delete; | 
 |   Parser(const Parser&) = delete; | 
 |   Parser& operator=(const Parser&) = delete; | 
 |  | 
 |   bool is_valid() const { return is_valid_; } | 
 |  | 
 |   // GetTag sets |*out_data| and |*out_len| to reflect the location (within the | 
 |   // data supplied to the constructor) of the tag |tag|, if found.  Returns true | 
 |   // if |tag| is found. | 
 |   bool GetTag(const uint8_t** out_data, size_t* out_len, tag_t tag) const; | 
 |  | 
 |   // GetFixedLen is a specialization of |GetTag| that returns true only if the | 
 |   // data tagged by |tag| is |expected_len| bytes long. | 
 |   bool GetFixedLen(const uint8_t** out_data, tag_t tag, | 
 |                    size_t expected_len) const; | 
 |  | 
 |   // Get is a specialization of |GetFixedLen| that expects |tag| to tag a value | 
 |   // of type |T|.  The tagged value is assigned to |*out_value|. | 
 |   template <typename T> | 
 |   bool Get(T* out_value, tag_t tag) const; | 
 |  | 
 |  private: | 
 |   bool is_valid_ = false; | 
 |   size_t num_tags_; | 
 |   const uint8_t* offsets_;  // |NumMessageOffsets| offsets into |data_|. | 
 |   const uint8_t* tags_;        // |num_tags_| 32-bit tags. | 
 |   const uint8_t* data_;      // |len_| bytes. | 
 |   size_t len_; | 
 | }; | 
 |  | 
 | // Builder creates a time server response. | 
 | class Builder { | 
 |  public: | 
 |   Builder() = delete; | 
 |   Builder(const Builder&) = delete; | 
 |   Builder& operator=(const Builder&) = delete; | 
 |  | 
 |   // Prepares to write tags and data to a buffer |out| of |out_len| bytes. | 
 |   Builder(uint8_t* out, size_t out_len, size_t num_tags); | 
 |  | 
 |   // AddTag adds the tag |tag| to the response, which must be greater than any | 
 |   // previously added tag, and sets |*out_data| to an address where |len| bytes | 
 |   // may be written.  Returns true iff the tag may be written. | 
 |   bool AddTag(uint8_t** out_data, tag_t tag, size_t len); | 
 |  | 
 |   // AddTagData is a specialization of |AddTag| that copies the |len| bytes | 
 |   // pointed to by |data| into the response.  Returns true iff the tag was | 
 |   // written. | 
 |   bool AddTagData(tag_t tag, const uint8_t* data, size_t len); | 
 |  | 
 |   // Finish returns true if the response is valid, and sets |out_len| to the | 
 |   // size of the response.  After calling |Finish| all subsequent calls will | 
 |   // fail. | 
 |   bool Finish(size_t* out_len); | 
 |  | 
 |  private: | 
 |   const size_t num_tags_; | 
 |   const size_t header_len_; | 
 |   uint8_t* const offsets_; | 
 |   uint8_t* const tags_; | 
 |  | 
 |   uint8_t* data_;      // Offset of next |AddTag|. | 
 |   size_t len_;         // Bytes remaining in the output buffer. | 
 |   size_t offset_ = 0;  // Offset of data for next tag. | 
 |  | 
 |   size_t tag_i_ = 0;  // Index of next tag. | 
 |   tag_t previous_tag_; | 
 |   bool have_previous_tag_ = false; | 
 |  | 
 |   bool valid_ = false; | 
 | }; | 
 |  | 
 | // Computes the SHA-512 hash of a Merkle tree leaf, i.e. a client's nonce, as | 
 | // 0||nonce.  |in| is assumed to point to |kNonceLength| bytes and |out| is | 
 | // assumed to have space for |SHA512_DIGEST_LENGTH| bytes. | 
 | void HashLeaf(uint8_t* out, const uint8_t* in); | 
 |  | 
 | // Computes the SHA-512 hash of a Merkle tree node as 1||left||right.  |left|, | 
 | // |right|, and |out| are assumed to point to |SHA512_DIGEST_LENGTH| bytes. | 
 | void HashNode(uint8_t* out, const uint8_t* left, const uint8_t* right); | 
 |  | 
 | }  // namespace roughtime | 
 |  | 
 | #endif  // SECURITY_ROUGHTIME_PROTOCOL_H_ |