• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/cert/ct_log_response_parser.h"
6 
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_value_converter.h"
10 #include "base/logging.h"
11 #include "base/strings/string_piece.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "net/cert/ct_serialization.h"
15 #include "net/cert/signed_tree_head.h"
16 
17 namespace net {
18 
19 namespace ct {
20 
21 namespace {
22 
23 // Structure for making JSON decoding easier. The string fields
24 // are base64-encoded so will require further decoding.
25 struct JsonSignedTreeHead {
26   int tree_size;
27   double timestamp;
28   std::string sha256_root_hash;
29   DigitallySigned signature;
30 
31   static void RegisterJSONConverter(
32       base::JSONValueConverter<JsonSignedTreeHead>* converted);
33 };
34 
ConvertSHA256RootHash(const base::StringPiece & s,std::string * result)35 bool ConvertSHA256RootHash(const base::StringPiece& s, std::string* result) {
36   if (!base::Base64Decode(s, result)) {
37     DVLOG(1) << "Failed decoding sha256_root_hash";
38     return false;
39   }
40 
41   if (result->length() != kSthRootHashLength) {
42     DVLOG(1) << "sha256_root_hash is expected to be 32 bytes, but is "
43              << result->length() << " bytes.";
44     return false;
45   }
46 
47   return true;
48 }
49 
ConvertTreeHeadSignature(const base::StringPiece & s,DigitallySigned * result)50 bool ConvertTreeHeadSignature(const base::StringPiece& s,
51                               DigitallySigned* result) {
52   std::string tree_head_signature;
53   if (!base::Base64Decode(s, &tree_head_signature)) {
54     DVLOG(1) << "Failed decoding tree_head_signature";
55     return false;
56   }
57 
58   base::StringPiece sp(tree_head_signature);
59   if (!DecodeDigitallySigned(&sp, result)) {
60     DVLOG(1) << "Failed decoding signature to DigitallySigned";
61     return false;
62   }
63   return true;
64 }
65 
RegisterJSONConverter(base::JSONValueConverter<JsonSignedTreeHead> * converter)66 void JsonSignedTreeHead::RegisterJSONConverter(
67     base::JSONValueConverter<JsonSignedTreeHead>* converter) {
68   converter->RegisterIntField("tree_size", &JsonSignedTreeHead::tree_size);
69   converter->RegisterDoubleField("timestamp", &JsonSignedTreeHead::timestamp);
70   converter->RegisterCustomField("sha256_root_hash",
71                                  &JsonSignedTreeHead::sha256_root_hash,
72                                  &ConvertSHA256RootHash);
73   converter->RegisterCustomField<DigitallySigned>(
74       "tree_head_signature",
75       &JsonSignedTreeHead::signature,
76       &ConvertTreeHeadSignature);
77 }
78 
IsJsonSTHStructurallyValid(const JsonSignedTreeHead & sth)79 bool IsJsonSTHStructurallyValid(const JsonSignedTreeHead& sth) {
80   if (sth.tree_size < 0) {
81     DVLOG(1) << "Tree size in Signed Tree Head JSON is negative: "
82              << sth.tree_size;
83     return false;
84   }
85 
86   if (sth.timestamp < 0) {
87     DVLOG(1) << "Timestamp in Signed Tree Head JSON is negative: "
88              << sth.timestamp;
89     return false;
90   }
91 
92   if (sth.sha256_root_hash.empty()) {
93     DVLOG(1) << "Missing SHA256 root hash from Signed Tree Head JSON.";
94     return false;
95   }
96 
97   if (sth.signature.signature_data.empty()) {
98     DVLOG(1) << "Missing SHA256 root hash from Signed Tree Head JSON.";
99     return false;
100   }
101 
102   return true;
103 }
104 
105 }  // namespace
106 
FillSignedTreeHead(const base::StringPiece & json_signed_tree_head,SignedTreeHead * signed_tree_head)107 bool FillSignedTreeHead(const base::StringPiece& json_signed_tree_head,
108                         SignedTreeHead* signed_tree_head) {
109   base::JSONReader json_reader;
110   scoped_ptr<base::Value> json(json_reader.Read(json_signed_tree_head));
111   if (json.get() == NULL) {
112     DVLOG(1) << "Empty Signed Tree Head JSON.";
113     return false;
114   }
115 
116   JsonSignedTreeHead parsed_sth;
117   base::JSONValueConverter<JsonSignedTreeHead> converter;
118   if (!converter.Convert(*json.get(), &parsed_sth)) {
119     DVLOG(1) << "Invalid Signed Tree Head JSON.";
120     return false;
121   }
122 
123   if (!IsJsonSTHStructurallyValid(parsed_sth))
124     return false;
125 
126   signed_tree_head->version = SignedTreeHead::V1;
127   signed_tree_head->tree_size = parsed_sth.tree_size;
128   signed_tree_head->timestamp =
129       base::Time::UnixEpoch() +
130       base::TimeDelta::FromMilliseconds(parsed_sth.timestamp);
131   signed_tree_head->signature = parsed_sth.signature;
132   memcpy(signed_tree_head->sha256_root_hash,
133          parsed_sth.sha256_root_hash.c_str(),
134          kSthRootHashLength);
135   return true;
136 }
137 
138 }  // namespace ct
139 
140 }  // namespace net
141