Home | History | Annotate | Download | only in cert
      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 
     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 
     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 
     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 
     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 
    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