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
17namespace net {
18
19namespace ct {
20
21namespace {
22
23// Structure for making JSON decoding easier. The string fields
24// are base64-encoded so will require further decoding.
25struct 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
35bool 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
50bool 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
66void 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
79bool 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
107bool 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