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