--- a/security/certverifier/CTKnownLogs.h
+++ b/security/certverifier/CTKnownLogs.h
@@ -4,91 +4,121 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This file was automatically generated by getCTKnownLogs.py. */
#ifndef CTKnownLogs_h
#define CTKnownLogs_h
+#include "CTLog.h"
+
#include <stddef.h>
-struct CTLogInfo {
- const char* const logName;
- const char* const logUrl;
- const char* const logKey;
- const size_t logKeyLength;
+struct CTLogInfo
+{
+ const char* const name;
+ // Index within kCTLogOperatorList.
+ const mozilla::ct::CTLogStatus status;
+ // 0 for qualified logs, disqualification time for disqualified logs
+ // (in milliseconds, measured since the epoch, ignoring leap seconds).
+ const uint64_t disqualificationTime;
+ const size_t operatorIndex;
+ const char* const key;
+ const size_t keyLength;
+};
+
+struct CTLogOperatorInfo
+{
+ const char* const name;
+ const mozilla::ct::CTLogOperatorId id;
};
const CTLogInfo kCTLogList[] = {
{ "Google 'Pilot' log",
- "https://ct.googleapis.com/pilot/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 0, // operated by Google
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x7d\xa8\x4b\x12\x29\x80\xa3\x3d\xad"
"\xd3\x5a\x77\xb8\xcc\xe2\x88\xb3\xa5\xfd\xf1\xd3\x0c\xcd\x18\x0c\xe8\x41"
"\x46\xe8\x81\x01\x1b\x15\xe1\x4b\xf1\x1b\x62\xdd\x36\x0a\x08\x18\xba\xed"
"\x0b\x35\x84\xd0\x9e\x40\x3c\x2d\x9e\x9b\x82\x65\xbd\x1f\x04\x10\x41\x4c"
"\xa0",
91 },
{ "Google 'Aviator' log",
- "https://ct.googleapis.com/aviator/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 0, // operated by Google
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xd7\xf4\xcc\x69\xb2\xe4\x0e\x90\xa3"
"\x8a\xea\x5a\x70\x09\x4f\xef\x13\x62\xd0\x8d\x49\x60\xff\x1b\x40\x50\x07"
"\x0c\x6d\x71\x86\xda\x25\x49\x8d\x65\xe1\x08\x0d\x47\x34\x6b\xbd\x27\xbc"
"\x96\x21\x3e\x34\xf5\x87\x76\x31\xb1\x7f\x1d\xc9\x85\x3b\x0d\xf7\x1f\x3f"
"\xe9",
91 },
{ "DigiCert Log Server",
- "https://ct1.digicert-ct.com/log/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 1, // operated by DigiCert
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x02\x46\xc5\xbe\x1b\xbb\x82\x40\x16"
"\xe8\xc1\xd2\xac\x19\x69\x13\x59\xf8\xf8\x70\x85\x46\x40\xb9\x38\xb0\x23"
"\x82\xa8\x64\x4c\x7f\xbf\xbb\x34\x9f\x4a\x5f\x28\x8a\xcf\x19\xc4\x00\xf6"
"\x36\x06\x93\x65\xed\x4c\xf5\xa9\x21\x62\x5a\xd8\x91\xeb\x38\x24\x40\xac"
"\xe8",
91 },
{ "Google 'Rocketeer' log",
- "https://ct.googleapis.com/rocketeer/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 0, // operated by Google
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x20\x5b\x18\xc8\x3c\xc1\x8b\xb3\x31"
"\x08\x00\xbf\xa0\x90\x57\x2b\xb7\x47\x8c\x6f\xb5\x68\xb0\x8e\x90\x78\xe9"
"\xa0\x73\xea\x4f\x28\x21\x2e\x9c\xc0\xf4\x16\x1b\xaa\xf9\xd5\xd7\xa9\x80"
"\xc3\x4e\x2f\x52\x3c\x98\x01\x25\x46\x24\x25\x28\x23\x77\x2d\x05\xc2\x40"
"\x7a",
91 },
{ "Certly.IO log",
- "https://log.certly.io/",
+ mozilla::ct::CTLogStatus::Disqualified,
+ 1460678400000, // Date.parse("2016-04-15T00:00:00Z")
+ 2, // operated by Certly
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x0b\x23\xcb\x85\x62\x98\x61\x48\x04"
"\x73\xeb\x54\x5d\xf3\xd0\x07\x8c\x2d\x19\x2d\x8c\x36\xf5\xeb\x8f\x01\x42"
"\x0a\x7c\x98\x26\x27\xc1\xb5\xdd\x92\x93\xb0\xae\xf8\x9b\x3d\x0c\xd8\x4c"
"\x4e\x1d\xf9\x15\xfb\x47\x68\x7b\xba\x66\xb7\x25\x9c\xd0\x4a\xc2\x66\xdb"
"\x48",
91 },
{ "Izenpe log",
- "https://ct.izenpe.com/",
+ mozilla::ct::CTLogStatus::Disqualified,
+ 1464566400000, // Date.parse("2016-05-30T00:00:00Z")
+ 3, // operated by Izenpe
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x27\x64\x39\x0c\x2d\xdc\x50\x18\xf8"
"\x21\x00\xa2\x0e\xed\x2c\xea\x3e\x75\xba\x9f\x93\x64\x09\x00\x11\xc4\x11"
"\x17\xab\x5c\xcf\x0f\x74\xac\xb5\x97\x90\x93\x00\x5b\xb8\xeb\xf7\x27\x3d"
"\xd9\xb2\x0a\x81\x5f\x2f\x0d\x75\x38\x94\x37\x99\x1e\xf6\x07\x76\xe0\xee"
"\xbe",
91 },
{ "Symantec log",
- "https://ct.ws.symantec.com/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 4, // operated by Symantec
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x96\xea\xac\x1c\x46\x0c\x1b\x55\xdc"
"\x0d\xfc\xb5\x94\x27\x46\x57\x42\x70\x3a\x69\x18\xe2\xbf\x3b\xc4\xdb\xab"
"\xa0\xf4\xb6\x6c\xc0\x53\x3f\x4d\x42\x10\x33\xf0\x58\x97\x8f\x6b\xbe\x72"
"\xf4\x2a\xec\x1c\x42\xaa\x03\x2f\x1a\x7e\x28\x35\x76\x99\x08\x3d\x21\x14"
"\x86",
91 },
{ "Venafi log",
- "https://ctlog.api.venafi.com/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 5, // operated by Venafi
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
"\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\x5a\x48"
"\x1f\x17\x52\x95\x35\xcb\xa3\x5b\x3a\x1f\x53\x82\x76\x94\xa3\xff\x80\xf2"
"\x1c\x37\x3c\xc0\xb1\xbd\xc1\x59\x8b\xab\x2d\x65\x93\xd7\xf3\xe0\x04\xd5"
"\x9a\x6f\xbf\xd6\x23\x76\x36\x4f\x23\x99\xcb\x54\x28\xad\x8c\x15\x4b\x65"
"\x59\x76\x41\x4a\x9c\xa6\xf7\xb3\x3b\x7e\xb1\xa5\x49\xa4\x17\x51\x6c\x80"
"\xdc\x2a\x90\x50\x4b\x88\x24\xe9\xa5\x12\x32\x93\x04\x48\x90\x02\xfa\x5f"
"\x0e\x30\x87\x8e\x55\x76\x05\xee\x2a\x4c\xce\xa3\x6a\x69\x09\x6e\x25\xad"
@@ -98,26 +128,30 @@ const CTLogInfo kCTLogList[] = {
"\x5b\xe8\x81\xcd\xfd\x92\x68\xe7\xf3\x06\xf0\xe9\x72\x84\xee\x01\xa5\xb1"
"\xd8\x33\xda\xce\x83\xa5\xdb\xc7\xcf\xd6\x16\x7e\x90\x75\x18\xbf\x16\xdc"
"\x32\x3b\x6d\x8d\xab\x82\x17\x1f\x89\x20\x8d\x1d\x9a\xe6\x4d\x23\x08\xdf"
"\x78\x6f\xc6\x05\xbf\x5f\xae\x94\x97\xdb\x5f\x64\xd4\xee\x16\x8b\xa3\x84"
"\x6c\x71\x2b\xf1\xab\x7f\x5d\x0d\x32\xee\x04\xe2\x90\xec\x41\x9f\xfb\x39"
"\xc1\x02\x03\x01\x00\x01",
294 },
{ "Symantec 'Vega' log",
- "https://vega.ws.symantec.com/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 4, // operated by Symantec
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xea\x95\x9e\x02\xff\xee\xf1\x33\x6d"
"\x4b\x87\xbc\xcd\xfd\x19\x17\x62\xff\x94\xd3\xd0\x59\x07\x3f\x02\x2d\x1c"
"\x90\xfe\xc8\x47\x30\x3b\xf1\xdd\x0d\xb8\x11\x0c\x5d\x1d\x86\xdd\xab\xd3"
"\x2b\x46\x66\xfb\x6e\x65\xb7\x3b\xfd\x59\x68\xac\xdf\xa6\xf8\xce\xd2\x18"
"\x4d",
91 },
{ "CNNIC CT log",
- "https://ctserver.cnnic.cn/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 6, // operated by CNNIC
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
"\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xbf\xb5\x08"
"\x61\x9a\x29\x32\x04\xd3\x25\x63\xe9\xd8\x85\xe1\x86\xe0\x1f\xd6\x5e\x9a"
"\xf7\x33\x3b\x80\x1b\xe7\xb6\x3e\x5f\x2d\xa1\x66\xf6\x95\x4a\x84\xa6\x21"
"\x56\x79\xe8\xf7\x85\xee\x5d\xe3\x7c\x12\xc0\xe0\x89\x22\x09\x22\x3e\xba"
"\x16\x95\x06\xbd\xa8\xb9\xb1\xa9\xb2\x7a\xd6\x61\x2e\x87\x11\xb9\x78\x40"
"\x89\x75\xdb\x0c\xdc\x90\xe0\xa4\x79\xd6\xd5\x5e\x6e\xd1\x2a\xdb\x34\xf4"
"\x99\x3f\x65\x89\x3b\x46\xc2\x29\x2c\x15\x07\x1c\xc9\x4b\x1a\x54\xf8\x6c"
@@ -127,28 +161,44 @@ const CTLogInfo kCTLogList[] = {
"\xb2\xe5\x9a\x6c\x0d\xc5\x1c\xa5\x8b\xf7\x3f\x30\xaf\xb9\x01\x91\xb7\x69"
"\x12\x12\xe5\x83\x61\xfe\x34\x00\xbe\xf6\x71\x8a\xc7\xeb\x50\x92\xe8\x59"
"\xfe\x15\x91\xeb\x96\x97\xf8\x23\x54\x3f\x2d\x8e\x07\xdf\xee\xda\xb3\x4f"
"\xc8\x3c\x9d\x6f\xdf\x3c\x2c\x43\x57\xa1\x47\x0c\x91\x04\xf4\x75\x4d\xda"
"\x89\x81\xa4\x14\x06\x34\xb9\x98\xc3\xda\xf1\xfd\xed\x33\x36\xd3\x16\x2d"
"\x35\x02\x03\x01\x00\x01",
294 },
{ "WoSign log",
- "https://ctlog.wosign.com/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 7, // operated by WoSign
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xcc\x11\x88\x7b\x2d\x66\xcb\xae\x8f"
"\x4d\x30\x66\x27\x19\x25\x22\x93\x21\x46\xb4\x2f\x01\xd3\xc6\xf9\x2b\xd5"
"\xc8\xba\x73\x9b\x06\xa2\xf0\x8a\x02\x9c\xd0\x6b\x46\x18\x30\x85\xba\xe9"
"\x24\x8b\x0e\xd1\x5b\x70\x28\x0c\x7e\xf1\x3a\x45\x7f\x5a\xf3\x82\x42\x60"
"\x31",
91 },
{ "StartCom log",
- "https://ct.startssl.com/",
+ mozilla::ct::CTLogStatus::Included,
+ 0, // no disqualification time
+ 8, // operated by StartCom
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
"\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x48\xf3\x59\xf3\xf6\x05\x18\xd3\xdb"
"\xb2\xed\x46\x7e\xcf\xc8\x11\xb5\x57\xb1\xa8\xd6\x4c\xe6\x9f\xb7\x4a\x1a"
"\x14\x86\x43\xa9\x48\xb0\xcb\x5a\x3f\x3c\x4a\xca\xdf\xc4\x82\x14\x55\x9a"
"\xf8\xf7\x8e\x40\x55\xdc\xf4\xd2\xaf\xea\x75\x74\xfb\x4e\x7f\x60\x86\x2e"
"\x51",
91 }
};
+const CTLogOperatorInfo kCTLogOperatorList[] = {
+ { "Google", 0 },
+ { "DigiCert", 1 },
+ { "Certly", 2 },
+ { "Izenpe", 3 },
+ { "Symantec", 4 },
+ { "Venafi", 5 },
+ { "CNNIC", 7 },
+ { "WoSign", 8 },
+ { "StartCom", 9 }
+};
+
#endif // CTKnownLogs_h
new file mode 100644
--- /dev/null
+++ b/security/certverifier/CTLog.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef CTLog_h
+#define CTLog_h
+
+#include <stdint.h>
+
+namespace mozilla { namespace ct {
+
+// Signed integer sufficient to store the numeric ID of CT log operators
+// as assigned at https://www.certificate-transparency.org/known-logs .
+// The assigned IDs are 0-based positive integers, so you can use special
+// values (such as -1) to indicate a "null" or unknown log ID.
+typedef int16_t CTLogOperatorId;
+
+// Current status of a CT log in regard to its inclusion in the
+// Known Logs List such as https://www.certificate-transparency.org/known-logs
+enum class CTLogStatus
+{
+ // Status unknown or unavailable.
+ Unknown,
+ // Included in the list of known logs.
+ Included,
+ // Previously included, but disqualified at some point of time.
+ Disqualified,
+};
+
+} } // namespace mozilla::ct
+
+#endif // CTLog_h
--- a/security/certverifier/CTLogVerifier.cpp
+++ b/security/certverifier/CTLogVerifier.cpp
@@ -1,16 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CTLogVerifier.h"
+#include <stdint.h>
+
#include "CTSerialization.h"
#include "hasht.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "pkix/pkixnss.h"
#include "pkixutil.h"
namespace mozilla { namespace ct {
@@ -115,22 +117,43 @@ public:
}
DigitallySigned::SignatureAlgorithm mSignatureAlgorithm;
};
CTLogVerifier::CTLogVerifier()
: mSignatureAlgorithm(DigitallySigned::SignatureAlgorithm::Anonymous)
+ , mOperatorId(-1)
+ , mDisqualified(false)
+ , mDisqualificationTime(UINT64_MAX)
{
}
Result
-CTLogVerifier::Init(Input subjectPublicKeyInfo)
+CTLogVerifier::Init(Input subjectPublicKeyInfo,
+ CTLogOperatorId operatorId,
+ CTLogStatus logStatus,
+ uint64_t disqualificationTime)
{
+ switch (logStatus) {
+ case CTLogStatus::Included:
+ mDisqualified = false;
+ mDisqualificationTime = UINT64_MAX;
+ break;
+ case CTLogStatus::Disqualified:
+ mDisqualified = true;
+ mDisqualificationTime = disqualificationTime;
+ break;
+ case CTLogStatus::Unknown:
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported CTLogStatus");
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
SignatureParamsTrustDomain trustDomain;
Result rv = CheckSubjectPublicKeyInfo(subjectPublicKeyInfo, trustDomain,
EndEntityOrCA::MustBeEndEntity);
if (rv != Success) {
return rv;
}
mSignatureAlgorithm = trustDomain.mSignatureAlgorithm;
@@ -143,16 +166,17 @@ CTLogVerifier::Init(Input subjectPublicK
return Result::FATAL_ERROR_NO_MEMORY;
}
rv = DigestBufNSS(subjectPublicKeyInfo, DigestAlgorithm::sha256,
mKeyId.begin(), mKeyId.length());
if (rv != Success) {
return rv;
}
+ mOperatorId = operatorId;
return Success;
}
Result
CTLogVerifier::Verify(const LogEntry& entry,
const SignedCertificateTimestamp& sct)
{
if (mKeyId.empty() || sct.logId != mKeyId) {
--- a/security/certverifier/CTLogVerifier.h
+++ b/security/certverifier/CTLogVerifier.h
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CTLogVerifier_h
#define CTLogVerifier_h
+#include "CTLog.h"
#include "pkix/Input.h"
#include "pkix/pkix.h"
#include "SignedCertificateTimestamp.h"
#include "SignedTreeHead.h"
namespace mozilla { namespace ct {
// Verifies Signed Certificate Timestamps (SCTs) provided by a specific log
@@ -21,26 +22,38 @@ namespace mozilla { namespace ct {
// The verification functions return Success if the provided SCT has passed
// verification, ERROR_BAD_SIGNATURE if failed verification, or other result
// on error.
class CTLogVerifier
{
public:
CTLogVerifier();
- // Initializes the verifier with log-specific information.
+ // Initializes the verifier with log-specific information. Only the public
+ // key is used for verification, other parameters are purely informational.
// |subjectPublicKeyInfo| is a DER-encoded SubjectPublicKeyInfo.
+ // |operatorId| The numeric ID of the log operator as assigned at
+ // https://www.certificate-transparency.org/known-logs .
+ // |logStatus| Either "Included" or "Disqualified".
+ // |disqualificationTime| Disqualification timestamp (for disqualified logs).
// An error is returned if |subjectPublicKeyInfo| refers to an unsupported
// public key.
- pkix::Result Init(pkix::Input subjectPublicKeyInfo);
+ pkix::Result Init(pkix::Input subjectPublicKeyInfo,
+ CTLogOperatorId operatorId,
+ CTLogStatus logStatus,
+ uint64_t disqualificationTime);
// Returns the log's key ID, which is a SHA256 hash of its public key.
// See RFC 6962, Section 3.2.
const Buffer& keyId() const { return mKeyId; }
+ CTLogOperatorId operatorId() const { return mOperatorId; }
+ bool isDisqualified() const { return mDisqualified; }
+ uint64_t disqualificationTime() const { return mDisqualificationTime; }
+
// Verifies that |sct| contains a valid signature for |entry|.
// |sct| must be signed by the verifier's log.
pkix::Result Verify(const LogEntry& entry,
const SignedCertificateTimestamp& sct);
// Verifies the signature in |sth|.
// |sth| must be signed by the verifier's log.
pkix::Result VerifySignedTreeHead(const SignedTreeHead& sth);
@@ -56,13 +69,16 @@ private:
// Returns Success if passed verification, ERROR_BAD_SIGNATURE if failed
// verification, or other result on error.
pkix::Result VerifySignature(pkix::Input data, pkix::Input signature);
pkix::Result VerifySignature(const Buffer& data, const Buffer& signature);
Buffer mSubjectPublicKeyInfo;
Buffer mKeyId;
DigitallySigned::SignatureAlgorithm mSignatureAlgorithm;
+ CTLogOperatorId mOperatorId;
+ bool mDisqualified;
+ uint64_t mDisqualificationTime;
};
} } // namespace mozilla::ct
#endif // CTLogVerifier_h
--- a/security/certverifier/CTVerifyResult.cpp
+++ b/security/certverifier/CTVerifyResult.cpp
@@ -8,16 +8,18 @@
#include <stdint.h>
namespace mozilla { namespace ct {
VerifiedSCT::VerifiedSCT()
: status(Status::None)
, origin(Origin::Unknown)
+ , logOperatorId(-1)
+ , logDisqualificationTime(UINT64_MAX)
{
}
void
CTVerifyResult::Reset()
{
verifiedScts.clear();
decodingErrors = 0;
--- a/security/certverifier/CTVerifyResult.h
+++ b/security/certverifier/CTVerifyResult.h
@@ -2,53 +2,61 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CTVerifyResult_h
#define CTVerifyResult_h
+#include "CTLog.h"
#include "mozilla/Vector.h"
#include "SignedCertificateTimestamp.h"
namespace mozilla { namespace ct {
// Holds a verified Signed Certificate Timestamp along with the verification
// status (e.g. valid/invalid) and additional information related to the
// verification.
struct VerifiedSCT
{
VerifiedSCT();
// The original SCT.
SignedCertificateTimestamp sct;
- enum class Status {
+ enum class Status
+ {
None,
// The SCT is from a known log, and the signature is valid.
Valid,
+ // The SCT is from a known disqualified log, and the signature is valid.
+ // For the disqualification time of the log see |logDisqualificationTime|.
+ ValidFromDisqualifiedLog,
// The SCT is from an unknown log and can not be verified.
UnknownLog,
// The SCT is from a known log, but the signature is invalid.
InvalidSignature,
// The SCT signature is valid, but the timestamp is in the future.
// Such SCTs are considered invalid (see RFC 6962, Section 5.2).
InvalidTimestamp,
};
- enum class Origin {
+ enum class Origin
+ {
Unknown,
Embedded,
TLSExtension,
OCSPResponse,
};
Status status;
Origin origin;
+ CTLogOperatorId logOperatorId;
+ uint64_t logDisqualificationTime;
};
typedef Vector<VerifiedSCT> VerifiedSCTList;
// Holds Signed Certificate Timestamps verification results.
class CTVerifyResult
{
public:
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -155,24 +155,27 @@ BuildCertChainForOneKeyUsage(NSSCertDBTr
void
CertVerifier::LoadKnownCTLogs()
{
mCTVerifier = MakeUnique<MultiLogCTVerifier>();
for (const CTLogInfo& log : kCTLogList) {
Input publicKey;
Result rv = publicKey.Init(
- BitwiseCast<const uint8_t*, const char*>(log.logKey), log.logKeyLength);
+ BitwiseCast<const uint8_t*, const char*>(log.key), log.keyLength);
if (rv != Success) {
MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log");
continue;
}
CTLogVerifier logVerifier;
- rv = logVerifier.Init(publicKey);
+ const CTLogOperatorInfo& logOperator =
+ kCTLogOperatorList[log.operatorIndex];
+ rv = logVerifier.Init(publicKey, logOperator.id, log.status,
+ log.disqualificationTime);
if (rv != Success) {
MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
continue;
}
rv = mCTVerifier->AddLog(Move(logVerifier));
if (rv != Success) {
MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
@@ -264,43 +267,47 @@ CertVerifier::VerifySignedCertificateTim
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("SCT verification failed with fatal error %i\n", rv));
return rv;
}
if (MOZ_LOG_TEST(gCertVerifierLog, LogLevel::Debug)) {
size_t validCount = 0;
size_t unknownLogCount = 0;
+ size_t disqualifiedLogCount = 0;
size_t invalidSignatureCount = 0;
size_t invalidTimestampCount = 0;
for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
switch (verifiedSct.status) {
case VerifiedSCT::Status::Valid:
validCount++;
break;
+ case VerifiedSCT::Status::ValidFromDisqualifiedLog:
+ disqualifiedLogCount++;
+ break;
case VerifiedSCT::Status::UnknownLog:
unknownLogCount++;
break;
case VerifiedSCT::Status::InvalidSignature:
invalidSignatureCount++;
break;
case VerifiedSCT::Status::InvalidTimestamp:
invalidTimestampCount++;
break;
case VerifiedSCT::Status::None:
default:
MOZ_ASSERT_UNREACHABLE("Unexpected SCT verification status");
}
}
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("SCT verification result: "
- "valid=%zu unknownLog=%zu "
+ "valid=%zu unknownLog=%zu disqualifiedLog=%zu "
"invalidSignature=%zu invalidTimestamp=%zu "
"decodingErrors=%zu\n",
- validCount, unknownLogCount,
+ validCount, unknownLogCount, disqualifiedLogCount,
invalidSignatureCount, invalidTimestampCount,
result.decodingErrors));
}
if (ctInfo) {
ctInfo->processedSCTs = true;
ctInfo->verifyResult = Move(result);
}
--- a/security/certverifier/MultiLogCTVerifier.cpp
+++ b/security/certverifier/MultiLogCTVerifier.cpp
@@ -150,16 +150,18 @@ MultiLogCTVerifier::VerifySingleSCT(Sign
}
if (!matchingLog) {
// SCT does not match any known log.
return StoreVerifiedSct(result, Move(verifiedSct),
VerifiedSCT::Status::UnknownLog);
}
+ verifiedSct.logOperatorId = matchingLog->operatorId();
+
if (!matchingLog->SignatureParametersMatch(verifiedSct.sct.signature)) {
// SCT signature parameters do not match the log's.
return StoreVerifiedSct(result, Move(verifiedSct),
VerifiedSCT::Status::InvalidSignature);
}
Result rv = matchingLog->Verify(expectedEntry, verifiedSct.sct);
if (rv != Success) {
@@ -178,14 +180,22 @@ MultiLogCTVerifier::VerifySingleSCT(Sign
// it does not matter.
Time sctTime =
TimeFromEpochInSeconds((verifiedSct.sct.timestamp + 999u) / 1000u);
if (sctTime > time) {
return StoreVerifiedSct(result, Move(verifiedSct),
VerifiedSCT::Status::InvalidTimestamp);
}
- // SCT verified ok.
+ // SCT verified ok, see if the log is qualified. Since SCTs from
+ // disqualified logs are treated as valid under certain circumstances (see
+ // the CT Policy), the log qualification check must be the last one we do.
+ if (matchingLog->isDisqualified()) {
+ verifiedSct.logDisqualificationTime = matchingLog->disqualificationTime();
+ return StoreVerifiedSct(result, Move(verifiedSct),
+ VerifiedSCT::Status::ValidFromDisqualifiedLog);
+ }
+
return StoreVerifiedSct(result, Move(verifiedSct),
VerifiedSCT::Status::Valid);
}
} } // namespace mozilla::ct
--- a/security/certverifier/SignedCertificateTimestamp.h
+++ b/security/certverifier/SignedCertificateTimestamp.h
@@ -82,17 +82,16 @@ struct SignedCertificateTimestamp
Buffer logId;
// "timestamp" is the current time in milliseconds, measured since the epoch,
// ignoring leap seconds. See RFC 6962, Section 3.2.
uint64_t timestamp;
Buffer extensions;
DigitallySigned signature;
};
-
inline pkix::Result BufferToInput(const Buffer& buffer, pkix::Input& input)
{
return input.Init(buffer.begin(), buffer.length());
}
inline pkix::Result InputToBuffer(pkix::Input input, Buffer& buffer)
{
buffer.clear();
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -2,16 +2,17 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'BRNameMatchingPolicy.h',
'CertVerifier.h',
+ 'CTLog.h',
'CTVerifyResult.h',
'OCSPCache.h',
'SignedCertificateTimestamp.h',
'SignedTreeHead.h',
]
UNIFIED_SOURCES += [
'BRNameMatchingPolicy.cpp',
--- a/security/certverifier/tests/gtest/CTLogVerifierTest.cpp
+++ b/security/certverifier/tests/gtest/CTLogVerifierTest.cpp
@@ -17,17 +17,20 @@ using namespace pkix;
class CTLogVerifierTest : public ::testing::Test
{
public:
void SetUp() override
{
// Does nothing if NSS is already initialized.
MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess);
- ASSERT_EQ(Success, mLog.Init(InputForBuffer(GetTestPublicKey())));
+ ASSERT_EQ(Success, mLog.Init(InputForBuffer(GetTestPublicKey()),
+ -1 /*operator id*/,
+ CTLogStatus::Included,
+ 0 /*disqualification time*/));
ASSERT_EQ(GetTestPublicKeyId(), mLog.keyId());
}
protected:
CTLogVerifier mLog;
};
TEST_F(CTLogVerifierTest, VerifiesCertSCT)
@@ -118,12 +121,15 @@ TEST_F(CTLogVerifierTest, DoesNotVerifyI
// Test that excess data after the public key is rejected.
TEST_F(CTLogVerifierTest, ExcessDataInPublicKey)
{
Buffer key = GetTestPublicKey();
MOZ_RELEASE_ASSERT(key.append("extra", 5));
CTLogVerifier log;
- EXPECT_NE(Success, log.Init(InputForBuffer(key)));
+ EXPECT_NE(Success, log.Init(InputForBuffer(key),
+ -1 /*operator id*/,
+ CTLogStatus::Included,
+ 0 /*disqualification time*/));
}
} } // namespace mozilla::ct
--- a/security/certverifier/tests/gtest/CTObjectsExtractorTest.cpp
+++ b/security/certverifier/tests/gtest/CTObjectsExtractorTest.cpp
@@ -24,17 +24,20 @@ public:
MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess);
mTestCert = GetDEREncodedX509Cert();
mEmbeddedCert = GetDEREncodedTestEmbeddedCert();
mCaCert = GetDEREncodedCACert();
mCaCertSPKI = ExtractCertSPKI(mCaCert);
Buffer logPublicKey = GetTestPublicKey();
- ASSERT_EQ(Success, mLog.Init(InputForBuffer(logPublicKey)));
+ ASSERT_EQ(Success, mLog.Init(InputForBuffer(logPublicKey),
+ -1 /*operator id*/,
+ CTLogStatus::Included,
+ 0 /*disqualification time*/));
}
protected:
Buffer mTestCert;
Buffer mEmbeddedCert;
Buffer mCaCert;
Buffer mCaCertSPKI;
CTLogVerifier mLog;
--- a/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
+++ b/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
@@ -21,25 +21,29 @@ namespace mozilla { namespace ct {
using namespace mozilla::pkix;
class MultiLogCTVerifierTest : public ::testing::Test
{
public:
MultiLogCTVerifierTest()
: mNow(Time::uninitialized)
+ , mLogOperatorID(123)
{}
void SetUp() override
{
// Does nothing if NSS is already initialized.
MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess);
CTLogVerifier log;
- ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
+ ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey()),
+ mLogOperatorID,
+ CTLogStatus::Included,
+ 0 /*disqualification time*/));
ASSERT_EQ(Success, mVerifier.AddLog(Move(log)));
mTestCert = GetDEREncodedX509Cert();
mEmbeddedCert = GetDEREncodedTestEmbeddedCert();
mCaCert = GetDEREncodedCACert();
mCaCertSPKI = ExtractCertSPKI(mCaCert);
mIntermediateCert = GetDEREncodedIntermediateCert();
mIntermediateCertSPKI = ExtractCertSPKI(mIntermediateCert);
@@ -50,16 +54,17 @@ public:
void CheckForSingleValidSCTInResult(const CTVerifyResult& result,
VerifiedSCT::Origin origin)
{
EXPECT_EQ(0U, result.decodingErrors);
ASSERT_EQ(1U, result.verifiedScts.length());
EXPECT_EQ(VerifiedSCT::Status::Valid, result.verifiedScts[0].status);
EXPECT_EQ(origin, result.verifiedScts[0].origin);
+ EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId);
}
// Writes an SCTList containing a single |sct| into |output|.
void EncodeSCTListForTesting(Input sct, Buffer& output)
{
Vector<Input> list;
ASSERT_TRUE(list.append(Move(sct)));
ASSERT_EQ(Success, EncodeSCTList(list, output));
@@ -93,16 +98,17 @@ protected:
MultiLogCTVerifier mVerifier;
Buffer mTestCert;
Buffer mEmbeddedCert;
Buffer mCaCert;
Buffer mCaCertSPKI;
Buffer mIntermediateCert;
Buffer mIntermediateCertSPKI;
Time mNow;
+ CTLogOperatorId mLogOperatorID;
};
// Test that an embedded SCT can be extracted and the extracted SCT contains
// the expected data. This tests the ExtractEmbeddedSCTList function from
// CTTestUtils.h that other tests here rely upon.
TEST_F(MultiLogCTVerifierTest, ExtractEmbeddedSCT)
{
SignedCertificateTimestamp sct;
@@ -218,9 +224,37 @@ TEST_F(MultiLogCTVerifierTest, Identifie
Input(), Input(), InputForBuffer(sctList),
mNow, result));
EXPECT_EQ(0U, result.decodingErrors);
ASSERT_EQ(1U, result.verifiedScts.length());
EXPECT_EQ(VerifiedSCT::Status::UnknownLog, result.verifiedScts[0].status);
}
+TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromDisqualifiedLog)
+{
+ MultiLogCTVerifier verifier;
+ CTLogVerifier log;
+ const uint64_t disqualificationTime = 12345u;
+ ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey()),
+ mLogOperatorID, CTLogStatus::Disqualified, disqualificationTime));
+ ASSERT_EQ(Success, verifier.AddLog(Move(log)));
+
+ Buffer sct(GetTestSignedCertificateTimestamp());
+ Buffer sctList;
+ EncodeSCTListForTesting(InputForBuffer(sct), sctList);
+
+ CTVerifyResult result;
+ ASSERT_EQ(Success,
+ verifier.Verify(InputForBuffer(mTestCert), Input(),
+ Input(), Input(), InputForBuffer(sctList),
+ mNow, result));
+
+ EXPECT_EQ(0U, result.decodingErrors);
+ ASSERT_EQ(1U, result.verifiedScts.length());
+ EXPECT_EQ(VerifiedSCT::Status::ValidFromDisqualifiedLog,
+ result.verifiedScts[0].status);
+ EXPECT_EQ(disqualificationTime,
+ result.verifiedScts[0].logDisqualificationTime);
+ EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId);
+}
+
} } // namespace mozilla::ct
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -1256,16 +1256,19 @@ GatherTelemetryForSingleSCT(const ct::Ve
verificationStatus = 2;
break;
case ct::VerifiedSCT::Status::InvalidSignature:
verificationStatus = 3;
break;
case ct::VerifiedSCT::Status::InvalidTimestamp:
verificationStatus = 4;
break;
+ case ct::VerifiedSCT::Status::ValidFromDisqualifiedLog:
+ verificationStatus = 5;
+ break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
}
Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
verificationStatus);
}
void
--- a/security/manager/ssl/nsSSLStatus.cpp
+++ b/security/manager/ssl/nsSSLStatus.cpp
@@ -350,16 +350,17 @@ nsSSLStatus::SetCertificateTransparencyI
bool hasUnknownLogSCTs = false;
bool hasInvalidSCTs = false;
for (const VerifiedSCT& verifiedSct : info.verifyResult.verifiedScts) {
switch (verifiedSct.status) {
case VerifiedSCT::Status::Valid:
hasValidSCTs = true;
break;
case VerifiedSCT::Status::UnknownLog:
+ case VerifiedSCT::Status::ValidFromDisqualifiedLog:
hasUnknownLogSCTs = true;
break;
case VerifiedSCT::Status::InvalidSignature:
case VerifiedSCT::Status::InvalidTimestamp:
hasInvalidSCTs = true;
break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
--- a/security/manager/tools/getCTKnownLogs.py
+++ b/security/manager/tools/getCTKnownLogs.py
@@ -1,23 +1,29 @@
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Parses a JSON file listing the known Certificate Transparency logs
-(as downloaded from https://www.certificate-transparency.org/known-logs)
-and generates a C++ header file to be included in Firefox.
+(log_list.json) and generates a C++ header file to be included in Firefox.
+
+The current log_list.json file available under security/manager/tools
+was originally downloaded from
+https://www.certificate-transparency.org/known-logs
+and edited to include the disqualification time for the disqualified logs using
+https://cs.chromium.org/chromium/src/net/cert/ct_known_logs_static-inc.h
"""
from __future__ import print_function
from string import Template
import argparse
import base64
+import datetime
import json
import os.path
import sys
import textwrap
import urllib2
OUTPUT_TEMPLATE = """\
@@ -27,72 +33,149 @@ OUTPUT_TEMPLATE = """\
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This file was automatically generated by $prog. */
#ifndef $include_guard
#define $include_guard
+#include "CTLog.h"
+
#include <stddef.h>
-struct CTLogInfo {
- const char* const logName;
- const char* const logUrl;
- const char* const logKey;
- const size_t logKeyLength;
+struct CTLogInfo
+{
+ const char* const name;
+ // Index within kCTLogOperatorList.
+ const mozilla::ct::CTLogStatus status;
+ // 0 for qualified logs, disqualification time for disqualified logs
+ // (in milliseconds, measured since the epoch, ignoring leap seconds).
+ const uint64_t disqualificationTime;
+ const size_t operatorIndex;
+ const char* const key;
+ const size_t keyLength;
+};
+
+struct CTLogOperatorInfo
+{
+ const char* const name;
+ const mozilla::ct::CTLogOperatorId id;
};
const CTLogInfo kCTLogList[] = {
$logs
};
+const CTLogOperatorInfo kCTLogOperatorList[] = {
+$operators
+};
+
#endif // $include_guard
"""
+def get_disqualification_time(time_str):
+ """
+ Convert a time string such as "2017-01-01T00:00:00Z" to an integer
+ representing milliseconds since the epoch.
+ Timezones in the string are not supported and will result in an exception.
+ """
+ t = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%SZ")
+ epoch = datetime.datetime.utcfromtimestamp(0)
+ seconds_since_epoch = (t - epoch).total_seconds()
+ return int(seconds_since_epoch * 1000)
+
+
def get_hex_lines(blob, width):
""" Convert a binary string to a multiline text of C escape sequences. """
text = "".join(["\\x{:02x}".format(ord(c)) for c in blob])
# When escaped, a single byte takes 4 chars (e.g. "\x00").
# Make sure we don't break an escaped byte between the lines.
return textwrap.wrap(text, width - width % 4)
+def get_operator_and_index(json_data, operator_id):
+ """ Return operator's entry from the JSON along with its array index. """
+ matches = [(operator, index) for (index, operator) in enumerate(
+ json_data["operators"]) if operator["id"] == operator_id]
+ assert len(matches) != 0, "No operators with id {0} defined.".format(
+ operator_id)
+ assert len(matches) == 1, "Found multiple operators with id {0}.".format(
+ operator_id)
+ return matches[0]
+
+
def get_log_info_structs(json_data):
""" Return array of CTLogInfo initializers for the known logs. """
tmpl = Template(textwrap.dedent("""\
{ $description,
- $url,
+ $status,
+ $disqualification_time, // $disqualification_time_comment
+ $operator_index, // $operator_comment
$indented_log_key,
$log_key_len }"""))
initializers = []
for log in json_data["logs"]:
log_key = base64.decodestring(log["key"])
+ # "operated_by" is a list, we assume here it always contains one item.
+ operated_by = log["operated_by"]
+ assert len(operated_by) == 1, "operated_by must contain one item."
+ operator, operator_index = get_operator_and_index(json_data,
+ operated_by[0])
+ if "disqualification_time" in log:
+ status = "mozilla::ct::CTLogStatus::Disqualified"
+ disqualification_time = get_disqualification_time(
+ log["disqualification_time"])
+ disqualification_time_comment = 'Date.parse("{0}")'.format(
+ log["disqualification_time"])
+ else:
+ status = "mozilla::ct::CTLogStatus::Included"
+ disqualification_time = 0
+ disqualification_time_comment = "no disqualification time"
initializers.append(tmpl.substitute(
# Use json.dumps for C-escaping strings.
# Not perfect but close enough.
description=json.dumps(log["description"]),
- url=json.dumps("https://{0}/".format(log["url"])),
+ operator_index=operator_index,
+ operator_comment="operated by {0}".
+ # The comment must not contain "/".
+ format(operator["name"]).replace("/", "|"),
+ status=status,
+ disqualification_time=disqualification_time,
+ disqualification_time_comment=disqualification_time_comment,
# Maximum line width is 80.
indented_log_key="\n".
join([' "{0}"'.format(l) for l in get_hex_lines(log_key, 74)]),
log_key_len=len(log_key)))
return initializers
+def get_log_operator_structs(json_data):
+ """ Return array of CTLogOperatorInfo initializers. """
+ tmpl = Template(" { $name, $id }")
+ initializers = []
+ for operator in json_data["operators"]:
+ initializers.append(tmpl.substitute(
+ name=json.dumps(operator["name"]),
+ id=operator["id"]))
+ return initializers
+
+
def generate_cpp_header_file(json_data, out_file):
""" Generate the C++ header file for the known logs. """
filename = os.path.basename(out_file.name)
include_guard = filename.replace(".", "_").replace("/", "_")
log_info_initializers = get_log_info_structs(json_data)
+ operator_info_initializers = get_log_operator_structs(json_data)
out_file.write(Template(OUTPUT_TEMPLATE).substitute(
prog=os.path.basename(sys.argv[0]),
include_guard=include_guard,
- logs=",\n".join(log_info_initializers)))
+ logs=",\n".join(log_info_initializers),
+ operators=",\n".join(operator_info_initializers)))
def run(args):
"""
Load the input JSON file and generate the C++ header according to the
command line arguments.
"""
if args.file:
@@ -121,26 +204,23 @@ def parse_arguments_and_run():
""" Parse the command line arguments and run the program. """
arg_parser = argparse.ArgumentParser(
description="Parses a JSON file listing the known "
"Certificate Transparency logs and generates "
"a C++ header file to be included in Firefox.",
epilog="Example: python %s --url" % os.path.basename(sys.argv[0]))
source_group = arg_parser.add_mutually_exclusive_group(required=True)
- source_group.add_argument("--file",
- help="Read the known CT logs JSON file from the "
- "specified location on the filesystem.")
- source_group.add_argument("--url", nargs="?",
- const="https://www.certificate-transparency.org/"
- "known-logs/log_list.json",
+ source_group.add_argument("--file", nargs="?",
+ const="log_list.json",
+ help="Read the known CT logs JSON data from the "
+ "specified local file (%(const)s by default).")
+ source_group.add_argument("--url",
help="Download the known CT logs JSON file "
- "from the specified URL. "
- "If no URL is given, download the file "
- "from %(const)s.")
+ "from the specified URL.")
arg_parser.add_argument("--out",
default="../../certverifier/CTKnownLogs.h",
help="Path and filename of the header file "
"to be generated. Defaults to %(default)s")
run(arg_parser.parse_args())
new file mode 100644
--- /dev/null
+++ b/security/manager/tools/log_list.json
@@ -0,0 +1,128 @@
+{
+ "operators": [
+ {
+ "name": "Google",
+ "id": 0
+ },
+ {
+ "name": "DigiCert",
+ "id": 1
+ },
+ {
+ "name": "Certly",
+ "id": 2
+ },
+ {
+ "name": "Izenpe",
+ "id": 3
+ },
+ {
+ "name": "Symantec",
+ "id": 4
+ },
+ {
+ "name": "Venafi",
+ "id": 5
+ },
+ {
+ "name": "CNNIC",
+ "id": 7
+ },
+ {
+ "name": "WoSign",
+ "id": 8
+ },
+ {
+ "name": "StartCom",
+ "id": 9
+ }
+ ],
+ "logs": [
+ {
+ "description": "Google 'Pilot' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==",
+ "url": "ct.googleapis.com/pilot",
+ "maximum_merge_delay": 86400,
+ "operated_by": [0]
+ },
+ {
+ "description": "Google 'Aviator' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==",
+ "url": "ct.googleapis.com/aviator",
+ "maximum_merge_delay": 86400,
+ "operated_by": [0]
+ },
+ {
+ "description": "DigiCert Log Server",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==",
+ "url": "ct1.digicert-ct.com/log",
+ "maximum_merge_delay": 86400,
+ "operated_by": [1]
+ },
+ {
+ "description": "Google 'Rocketeer' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==",
+ "url": "ct.googleapis.com/rocketeer",
+ "maximum_merge_delay": 86400,
+ "operated_by": [0]
+ },
+ {
+ "description": "Certly.IO log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==",
+ "url": "log.certly.io",
+ "maximum_merge_delay": 86400,
+ "operated_by": [2],
+ "disqualification_time": "2016-04-15T00:00:00Z"
+ },
+ {
+ "description": "Izenpe log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==",
+ "url": "ct.izenpe.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [3],
+ "disqualification_time": "2016-05-30T00:00:00Z"
+ },
+ {
+ "description": "Symantec log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==",
+ "url": "ct.ws.symantec.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [4]
+ },
+ {
+ "description": "Venafi log",
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB",
+ "url": "ctlog.api.venafi.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [5]
+ },
+ {
+ "description": "Symantec 'Vega' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6pWeAv/u8TNtS4e8zf0ZF2L/lNPQWQc/Ai0ckP7IRzA78d0NuBEMXR2G3avTK0Zm+25ltzv9WWis36b4ztIYTQ==",
+ "url": "vega.ws.symantec.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [4]
+ },
+ {
+ "description": "CNNIC CT log",
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7UIYZopMgTTJWPp2IXhhuAf1l6a9zM7gBvntj5fLaFm9pVKhKYhVnno94XuXeN8EsDgiSIJIj66FpUGvai5samyetZhLocRuXhAiXXbDNyQ4KR51tVebtEq2zT0mT9liTtGwiksFQccyUsaVPhsHq9gJ2IKZdWauVA2Fm5x9h8B9xKn/L/2IaMpkIYtd967TNTP/dLPgixN1PLCLaypvurDGSVDsuWabA3FHKWL9z8wr7kBkbdpEhLlg2H+NAC+9nGKx+tQkuhZ/hWR65aX+CNUPy2OB9/u2rNPyDydb988LENXoUcMkQT0dU3aiYGkFAY0uZjD2vH97TM20xYtNQIDAQAB",
+ "url": "ctserver.cnnic.cn",
+ "maximum_merge_delay": 86400,
+ "operated_by": [7]
+ },
+ {
+ "description": "WoSign log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBGIey1my66PTTBmJxklIpMhRrQvAdPG+SvVyLpzmwai8IoCnNBrRhgwhbrpJIsO0VtwKAx+8TpFf1rzgkJgMQ==",
+ "url": "ctlog.wosign.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [8]
+ },
+ {
+ "description": "StartCom log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESPNZ8/YFGNPbsu1Gfs/IEbVXsajWTOaft0oaFIZDqUiwy1o/PErK38SCFFWa+PeOQFXc9NKv6nV0+05/YIYuUQ==",
+ "url": "ct.startssl.com",
+ "maximum_merge_delay": 86400,
+ "operated_by": [9]
+ }
+ ]
+}
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8558,17 +8558,17 @@
},
"SSL_SCTS_VERIFICATION_STATUS": {
"alert_emails": ["seceng-telemetry@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 10,
"bug_numbers": [1293231],
"releaseChannelCollection": "opt-out",
- "description": "Verification status of Signed Certificate Timestamps received (0=Decoding error, 1=SCT verified, 2=SCT from unknown log, 3=Invalid SCT signature, 4=SCT timestamp is in the future)"
+ "description": "Verification status of Signed Certificate Timestamps received (0=Decoding error, 1=Valid SCT, 2=SCT from unknown log, 3=Invalid SCT signature, 4=SCT timestamp is in the future, 5=Valid SCT from a disqualified log)"
},
"SSL_SERVER_AUTH_EKU": {
"alert_emails": ["seceng-telemetry@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 10,
"description": "Presence of of the Server Authenticaton EKU in accepted SSL server certificates (0=No EKU, 1=EKU present and has id_kp_serverAuth, 2=EKU present and has id_kp_serverAuth as well as some other EKU, 3=EKU present but does not contain id_kp_serverAuth)"
},