1// Copyright 2013 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_signed_certificate_timestamp_log_param.h"
6
7#include <algorithm>
8#include <string>
9
10#include "base/base64.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/stringprintf.h"
13#include "base/values.h"
14#include "net/cert/ct_verify_result.h"
15#include "net/cert/signed_certificate_timestamp.h"
16
17namespace net {
18
19namespace {
20
21// Converts a numeric |origin| to text describing the SCT's origin
22const char* OriginToString(ct::SignedCertificateTimestamp::Origin origin) {
23  switch (origin) {
24    case ct::SignedCertificateTimestamp::SCT_EMBEDDED:
25      return "embedded_in_certificate";
26    case ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION:
27      return "tls_extension";
28    case ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE:
29      return "ocsp";
30    case ct::SignedCertificateTimestamp::SCT_ORIGIN_MAX:
31      break;
32  }
33
34  return "unknown";
35}
36
37// Converts a numeric |hash_algorithm| to its textual representation
38const char* HashAlgorithmToString(
39    ct::DigitallySigned::HashAlgorithm hash_algorithm) {
40  switch (hash_algorithm) {
41    case ct::DigitallySigned::HASH_ALGO_NONE:
42      return "NONE";
43    case ct::DigitallySigned::HASH_ALGO_MD5:
44      return "MD5";
45    case ct::DigitallySigned::HASH_ALGO_SHA1:
46      return "SHA1";
47    case ct::DigitallySigned::HASH_ALGO_SHA224:
48      return "SHA224";
49    case ct::DigitallySigned::HASH_ALGO_SHA256:
50      return "SHA256";
51    case ct::DigitallySigned::HASH_ALGO_SHA384:
52      return "SHA384";
53    case ct::DigitallySigned::HASH_ALGO_SHA512:
54      return "SHA512";
55  }
56
57  return "unknown";
58}
59
60// Converts a numeric |signature_algorithm| to its textual representation
61const char* SignatureAlgorithmToString(
62    ct::DigitallySigned::SignatureAlgorithm signature_algorithm) {
63  switch (signature_algorithm) {
64    case ct::DigitallySigned::SIG_ALGO_ANONYMOUS:
65      return "ANONYMOUS";
66    case ct::DigitallySigned::SIG_ALGO_RSA:
67      return "RSA";
68    case ct::DigitallySigned::SIG_ALGO_DSA:
69      return "DSA";
70    case ct::DigitallySigned::SIG_ALGO_ECDSA:
71      return "ECDSA";
72  }
73
74  return "unknown";
75}
76
77// Base64 encode the given |value| string and put it in |dict| with the
78// description |key|.
79void SetBinaryData(
80    const char* key,
81    const std::string& value,
82    base::DictionaryValue* dict) {
83  std::string b64_value;
84  base::Base64Encode(value, &b64_value);
85
86  dict->SetString(key, b64_value);
87}
88
89// Returns a dictionary where each key is a field of the SCT and its value
90// is this field's value in the SCT. This dictionary is meant to be used for
91// outputting a de-serialized SCT to the NetLog.
92base::DictionaryValue* SCTToDictionary(
93    const ct::SignedCertificateTimestamp& sct) {
94  base::DictionaryValue* out = new base::DictionaryValue();
95
96  out->SetString("origin", OriginToString(sct.origin));
97  out->SetInteger("version", sct.version);
98
99  SetBinaryData("log_id", sct.log_id, out);
100  base::TimeDelta time_since_unix_epoch =
101      sct.timestamp - base::Time::UnixEpoch();
102  out->SetString("timestamp",
103      base::Int64ToString(time_since_unix_epoch.InMilliseconds()));
104  SetBinaryData("extensions", sct.extensions, out);
105
106  out->SetString("hash_algorithm",
107                 HashAlgorithmToString(sct.signature.hash_algorithm));
108  out->SetString("signature_algorithm",
109                 SignatureAlgorithmToString(sct.signature.signature_algorithm));
110  SetBinaryData(
111      "signature_data", sct.signature.signature_data, out);
112
113  return out;
114}
115
116// Given a list of SCTs, return a ListValue instance where each item in the
117// list is a dictionary created by SCTToDictionary.
118base::ListValue* SCTListToPrintableValues(
119    const ct::SCTList& sct_list) {
120  base::ListValue* output_scts = new base::ListValue();
121  for (ct::SCTList::const_iterator it = sct_list.begin();
122       it != sct_list.end();
123       ++it)
124    output_scts->Append(SCTToDictionary(*(it->get())));
125
126  return output_scts;
127}
128
129}  // namespace
130
131base::Value* NetLogSignedCertificateTimestampCallback(
132    const ct::CTVerifyResult* ct_result, NetLog::LogLevel log_level) {
133  base::DictionaryValue* dict = new base::DictionaryValue();
134
135  dict->Set("verified_scts",
136            SCTListToPrintableValues(ct_result->verified_scts));
137
138  dict->Set("invalid_scts",
139            SCTListToPrintableValues(ct_result->invalid_scts));
140
141  dict->Set("unknown_logs_scts",
142            SCTListToPrintableValues(ct_result->unknown_logs_scts));
143
144  return dict;
145}
146
147base::Value* NetLogRawSignedCertificateTimestampCallback(
148    const std::string* embedded_scts,
149    const std::string* sct_list_from_ocsp,
150    const std::string* sct_list_from_tls_extension,
151    NetLog::LogLevel log_level) {
152  base::DictionaryValue* dict = new base::DictionaryValue();
153
154  SetBinaryData("embedded_scts", *embedded_scts, dict);
155  SetBinaryData("scts_from_ocsp_response", *sct_list_from_ocsp, dict);
156  SetBinaryData("scts_from_tls_extension", *sct_list_from_tls_extension, dict);
157
158  return dict;
159}
160
161}  // namespace net
162