Bug 1930690 - certificate transparency: support static-ct-api ("tiled") logs a=diannaS
Differential Revision: https://phabricator.services.mozilla.com/D258972
This commit is contained in:
committed by
dsmith@mozilla.com
parent
c68862e175
commit
e85c3d250f
@@ -219,7 +219,8 @@ void CertVerifier::LoadKnownCTLogs() {
|
|||||||
|
|
||||||
const CTLogOperatorInfo& logOperator =
|
const CTLogOperatorInfo& logOperator =
|
||||||
kCTLogOperatorList[log.operatorIndex];
|
kCTLogOperatorList[log.operatorIndex];
|
||||||
CTLogVerifier logVerifier(logOperator.id, log.state, log.timestamp);
|
CTLogVerifier logVerifier(logOperator.id, log.state, log.format,
|
||||||
|
log.timestamp);
|
||||||
rv = logVerifier.Init(publicKey);
|
rv = logVerifier.Init(publicKey);
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
|
MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
static const PRTime kCTExpirationTime = INT64_C(1759749898000000);
|
static const PRTime kCTExpirationTime = INT64_C(1759796803000000);
|
||||||
|
|
||||||
namespace mozilla::ct {
|
namespace mozilla::ct {
|
||||||
|
|
||||||
@@ -23,10 +23,16 @@ enum class CTLogState {
|
|||||||
Retired,
|
Retired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CTLogFormat {
|
||||||
|
RFC6962,
|
||||||
|
Tiled,
|
||||||
|
};
|
||||||
|
|
||||||
struct CTLogInfo {
|
struct CTLogInfo {
|
||||||
// See bug 1338873 about making these fields const.
|
// See bug 1338873 about making these fields const.
|
||||||
const char* name;
|
const char* name;
|
||||||
CTLogState state;
|
CTLogState state;
|
||||||
|
CTLogFormat format;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
// Index within kCTLogOperatorList.
|
// Index within kCTLogOperatorList.
|
||||||
size_t operatorIndex;
|
size_t operatorIndex;
|
||||||
@@ -41,7 +47,7 @@ struct CTLogOperatorInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const CTLogInfo kCTLogList[] = {
|
const CTLogInfo kCTLogList[] = {
|
||||||
{"Google 'Argon2025h1' log", CTLogState::Admissible,
|
{"Google 'Argon2025h1' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -51,7 +57,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xfb\xae\xbe\xc8\x23\x52\x20\x2b\xaa\x44\x05\xfe\x54\xf9\xd5\xf1\x1d\x45"
|
"\xfb\xae\xbe\xc8\x23\x52\x20\x2b\xaa\x44\x05\xfe\x54\xf9\xd5\xf1\x1d\x45"
|
||||||
"\x9a",
|
"\x9a",
|
||||||
91},
|
91},
|
||||||
{"Google 'Argon2025h2' log", CTLogState::Admissible,
|
{"Google 'Argon2025h2' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -61,7 +67,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x56\x4e\x98\xe8\xaa\x26\x29\x36\x1e\x28\x60\x6f\xeb\x15\x6e\xf7\x7c\xd0"
|
"\x56\x4e\x98\xe8\xaa\x26\x29\x36\x1e\x28\x60\x6f\xeb\x15\x6e\xf7\x7c\xd0"
|
||||||
"\xba",
|
"\xba",
|
||||||
91},
|
91},
|
||||||
{"Google 'Argon2026h1' log", CTLogState::Admissible,
|
{"Google 'Argon2026h1' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1727734767000, // 2024-09-30T22:19:27Z
|
1727734767000, // 2024-09-30T22:19:27Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -71,7 +77,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x06\x4f\x64\x58\x75\x14\x5d\x56\x52\xe6\x6a\x2b\x14\x4c\xec\x81\xd1\xea"
|
"\x06\x4f\x64\x58\x75\x14\x5d\x56\x52\xe6\x6a\x2b\x14\x4c\xec\x81\xd1\xea"
|
||||||
"\x3e",
|
"\x3e",
|
||||||
91},
|
91},
|
||||||
{"Google 'Argon2026h2' log", CTLogState::Admissible,
|
{"Google 'Argon2026h2' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1727734767000, // 2024-09-30T22:19:27Z
|
1727734767000, // 2024-09-30T22:19:27Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -81,7 +87,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xf5\x35\x50\x9c\xa1\xd3\x49\x4d\x13\xd5\x3b\x6a\x0e\xea\x45\x9d\x24\x13"
|
"\xf5\x35\x50\x9c\xa1\xd3\x49\x4d\x13\xd5\x3b\x6a\x0e\xea\x45\x9d\x24\x13"
|
||||||
"\x22",
|
"\x22",
|
||||||
91},
|
91},
|
||||||
{"Google 'Xenon2025h1' log", CTLogState::Admissible,
|
{"Google 'Xenon2025h1' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -91,7 +97,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x12\xe6\x54\x78\x50\xdc\xff\x6d\xfd\x1c\xa7\xb6\x3a\x1f\xf9\x26\xa9\x1b"
|
"\x12\xe6\x54\x78\x50\xdc\xff\x6d\xfd\x1c\xa7\xb6\x3a\x1f\xf9\x26\xa9\x1b"
|
||||||
"\xbd",
|
"\xbd",
|
||||||
91},
|
91},
|
||||||
{"Google 'Xenon2025h2' log", CTLogState::Admissible,
|
{"Google 'Xenon2025h2' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -101,7 +107,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xa0\x3e\x9d\x94\x1c\xb2\xb7\x4a\xf2\x51\xec\x40\xed\x62\x47\xa4\x03\x49"
|
"\xa0\x3e\x9d\x94\x1c\xb2\xb7\x4a\xf2\x51\xec\x40\xed\x62\x47\xa4\x03\x49"
|
||||||
"\x86",
|
"\x86",
|
||||||
91},
|
91},
|
||||||
{"Google 'Xenon2026h1' log", CTLogState::Admissible,
|
{"Google 'Xenon2026h1' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1727734767000, // 2024-09-30T22:19:27Z
|
1727734767000, // 2024-09-30T22:19:27Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -111,7 +117,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xeb\x03\x0a\x30\xcc\x63\x6c\xd9\x3c\xbe\xf5\x7b\x94\xba\x94\xd3\xbf\x88"
|
"\xeb\x03\x0a\x30\xcc\x63\x6c\xd9\x3c\xbe\xf5\x7b\x94\xba\x94\xd3\xbf\x88"
|
||||||
"\x4c",
|
"\x4c",
|
||||||
91},
|
91},
|
||||||
{"Google 'Xenon2026h2' log", CTLogState::Admissible,
|
{"Google 'Xenon2026h2' log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1727734767000, // 2024-09-30T22:19:27Z
|
1727734767000, // 2024-09-30T22:19:27Z
|
||||||
0, // operated by Google
|
0, // operated by Google
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -121,7 +127,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x8a\x72\x30\x65\x86\x43\x53\xdc\x11\x44\x18\x49\x98\x25\x68\xa7\x3c\x05"
|
"\x8a\x72\x30\x65\x86\x43\x53\xdc\x11\x44\x18\x49\x98\x25\x68\xa7\x3c\x05"
|
||||||
"\xbf",
|
"\xbf",
|
||||||
91},
|
91},
|
||||||
{"Cloudflare 'Nimbus2025'", CTLogState::Admissible,
|
{"Cloudflare 'Nimbus2025'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1702969200000, // 2023-12-19T07:00:00Z
|
1702969200000, // 2023-12-19T07:00:00Z
|
||||||
1, // operated by Cloudflare
|
1, // operated by Cloudflare
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -131,7 +137,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x81\x5b\x4a\x14\x41\xec\xaf\xa9\x5d\x0e\xab\x12\x19\x71\xcd\x43\xef\xbb"
|
"\x81\x5b\x4a\x14\x41\xec\xaf\xa9\x5d\x0e\xab\x12\x19\x71\xcd\x43\xef\xbb"
|
||||||
"\x97",
|
"\x97",
|
||||||
91},
|
91},
|
||||||
{"Cloudflare 'Nimbus2026'", CTLogState::Admissible,
|
{"Cloudflare 'Nimbus2026'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1731088800000, // 2024-11-08T18:00:00Z
|
1731088800000, // 2024-11-08T18:00:00Z
|
||||||
1, // operated by Cloudflare
|
1, // operated by Cloudflare
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -141,7 +147,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xbf\x91\x64\x46\x6e\x0e\x27\x13\xea\xbb\x6f\x46\x27\x58\x86\xef\x40\x21"
|
"\xbf\x91\x64\x46\x6e\x0e\x27\x13\xea\xbb\x6f\x46\x27\x58\x86\xef\x40\x21"
|
||||||
"\xa3",
|
"\xa3",
|
||||||
91},
|
91},
|
||||||
{"DigiCert Yeti2025 Log", CTLogState::Retired,
|
{"DigiCert Yeti2025 Log", CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
1753315200000, // 2025-07-24T00:00:00Z
|
1753315200000, // 2025-07-24T00:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -151,7 +157,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x95\x24\x7c\xd8\x91\x98\x48\x3b\xf0\xf0\xdf\x21\xf1\xb0\x81\x5a\x59\x25"
|
"\x95\x24\x7c\xd8\x91\x98\x48\x3b\xf0\xf0\xdf\x21\xf1\xb0\x81\x5a\x59\x25"
|
||||||
"\x43",
|
"\x43",
|
||||||
91},
|
91},
|
||||||
{"DigiCert Nessie2025 Log", CTLogState::Retired,
|
{"DigiCert Nessie2025 Log", CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
1744758000000, // 2025-04-15T23:00:00Z
|
1744758000000, // 2025-04-15T23:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -161,7 +167,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x75\x80\xb7\x53\xa7\x85\xd5\xbc\xab\x47\x06\x55\xdb\xb5\xdf\x88\xa1\x6f"
|
"\x75\x80\xb7\x53\xa7\x85\xd5\xbc\xab\x47\x06\x55\xdb\xb5\xdf\x88\xa1\x6f"
|
||||||
"\x38",
|
"\x38",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Wyvern2025h1' Log", CTLogState::Retired,
|
{"DigiCert 'Wyvern2025h1' Log", CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
1744670000000, // 2025-04-14T22:33:20Z
|
1744670000000, // 2025-04-14T22:33:20Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -171,7 +177,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x0d\x96\x58\x44\x9d\x3b\x8a\x80\xc5\xc8\xbe\xe1\x89\x46\x6b\x48\x4c\xd6"
|
"\x0d\x96\x58\x44\x9d\x3b\x8a\x80\xc5\xc8\xbe\xe1\x89\x46\x6b\x48\x4c\xd6"
|
||||||
"\x09",
|
"\x09",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Wyvern2025h2' Log", CTLogState::Admissible,
|
{"DigiCert 'Wyvern2025h2' Log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1724900983000, // 2024-08-29T03:09:43Z
|
1724900983000, // 2024-08-29T03:09:43Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -181,7 +187,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x1c\x63\xde\x95\xe2\x81\x69\x97\x8d\x1e\xa8\xb7\x66\x51\x25\x75\x4d\x78"
|
"\x1c\x63\xde\x95\xe2\x81\x69\x97\x8d\x1e\xa8\xb7\x66\x51\x25\x75\x4d\x78"
|
||||||
"\x2e",
|
"\x2e",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Wyvern2026h1'", CTLogState::Admissible,
|
{"DigiCert 'Wyvern2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1731024000000, // 2024-11-08T00:00:00Z
|
1731024000000, // 2024-11-08T00:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -191,7 +197,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xd5\xd1\x83\xf8\x7a\xdf\x1e\x07\xbc\x15\xcd\xc0\x4a\xcd\x2a\x31\x71\x07"
|
"\xd5\xd1\x83\xf8\x7a\xdf\x1e\x07\xbc\x15\xcd\xc0\x4a\xcd\x2a\x31\x71\x07"
|
||||||
"\x55",
|
"\x55",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Wyvern2026h2'", CTLogState::Admissible,
|
{"DigiCert 'Wyvern2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1731024000000, // 2024-11-08T00:00:00Z
|
1731024000000, // 2024-11-08T00:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -201,7 +207,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xde\x9b\x8c\x13\x92\xb7\xad\x3d\x0f\xa1\x9c\x8f\x48\xce\x74\x27\x18\x23"
|
"\xde\x9b\x8c\x13\x92\xb7\xad\x3d\x0f\xa1\x9c\x8f\x48\xce\x74\x27\x18\x23"
|
||||||
"\x99",
|
"\x99",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Sphinx2025h1' Log", CTLogState::Retired,
|
{"DigiCert 'Sphinx2025h1' Log", CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
1744670000000, // 2025-04-14T22:33:20Z
|
1744670000000, // 2025-04-14T22:33:20Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -211,7 +217,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x45\x31\x17\xd3\x8d\xf2\xe7\xce\x18\x11\x58\x98\x2c\x60\x6f\x58\x20\x36"
|
"\x45\x31\x17\xd3\x8d\xf2\xe7\xce\x18\x11\x58\x98\x2c\x60\x6f\x58\x20\x36"
|
||||||
"\x6e",
|
"\x6e",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Sphinx2025h2' Log", CTLogState::Admissible,
|
{"DigiCert 'Sphinx2025h2' Log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1724900983000, // 2024-08-29T03:09:43Z
|
1724900983000, // 2024-08-29T03:09:43Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -221,7 +227,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x1a\x27\x54\x85\x5d\xc1\x7b\x24\xa8\x34\xe3\xcd\x88\xce\xd4\x50\x1b\xbe"
|
"\x1a\x27\x54\x85\x5d\xc1\x7b\x24\xa8\x34\xe3\xcd\x88\xce\xd4\x50\x1b\xbe"
|
||||||
"\x69",
|
"\x69",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Sphinx2026h1'", CTLogState::Admissible,
|
{"DigiCert 'Sphinx2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1731024000000, // 2024-11-08T00:00:00Z
|
1731024000000, // 2024-11-08T00:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -231,7 +237,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xbc\xc3\x9e\x05\x02\x9a\x08\x01\xb5\x49\x23\x35\xc4\xd3\x50\x2b\x51\xe9"
|
"\xbc\xc3\x9e\x05\x02\x9a\x08\x01\xb5\x49\x23\x35\xc4\xd3\x50\x2b\x51\xe9"
|
||||||
"\xf4",
|
"\xf4",
|
||||||
91},
|
91},
|
||||||
{"DigiCert 'Sphinx2026h2'", CTLogState::Admissible,
|
{"DigiCert 'Sphinx2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1731024000000, // 2024-11-08T00:00:00Z
|
1731024000000, // 2024-11-08T00:00:00Z
|
||||||
2, // operated by DigiCert
|
2, // operated by DigiCert
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -241,7 +247,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x38\x8c\xa4\x38\x2e\xac\x95\x0c\xeb\xed\x4f\x64\xbc\x45\x42\xf7\x06\x7a"
|
"\x38\x8c\xa4\x38\x2e\xac\x95\x0c\xeb\xed\x4f\x64\xbc\x45\x42\xf7\x06\x7a"
|
||||||
"\xcd",
|
"\xcd",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Sabre2025h1'", CTLogState::Admissible,
|
{"Sectigo 'Sabre2025h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -251,7 +257,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x41\xae\x70\xb3\x31\xa2\xe3\xfa\x3d\x5f\x2c\x5d\x04\xcd\xb4\x9d\x55\xab"
|
"\x41\xae\x70\xb3\x31\xa2\xe3\xfa\x3d\x5f\x2c\x5d\x04\xcd\xb4\x9d\x55\xab"
|
||||||
"\x41",
|
"\x41",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Sabre2025h2'", CTLogState::Admissible,
|
{"Sectigo 'Sabre2025h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -261,7 +267,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xaf\x89\x8b\xf5\x58\xd8\xba\xeb\x7b\x83\x52\xe9\xf4\xe0\xa5\xcd\xcd\x92"
|
"\xaf\x89\x8b\xf5\x58\xd8\xba\xeb\x7b\x83\x52\xe9\xf4\xe0\xa5\xcd\xcd\x92"
|
||||||
"\xcc",
|
"\xcc",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Mammoth2025h1'", CTLogState::Admissible,
|
{"Sectigo 'Mammoth2025h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -271,7 +277,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x9b\x4e\x72\x62\x4b\x3c\x0c\x32\xdd\x86\xfb\xeb\x3e\x66\xcd\x77\x58\x5b"
|
"\x9b\x4e\x72\x62\x4b\x3c\x0c\x32\xdd\x86\xfb\xeb\x3e\x66\xcd\x77\x58\x5b"
|
||||||
"\xe5",
|
"\xe5",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Mammoth2025h2'", CTLogState::Admissible,
|
{"Sectigo 'Mammoth2025h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -281,7 +287,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xb1\x15\x67\x66\xa0\x7c\x0b\x5b\x62\x7f\x6c\x9a\x6a\x30\x9b\x68\x02\x16"
|
"\xb1\x15\x67\x66\xa0\x7c\x0b\x5b\x62\x7f\x6c\x9a\x6a\x30\x9b\x68\x02\x16"
|
||||||
"\x6f",
|
"\x6f",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Mammoth2026h1'", CTLogState::Admissible,
|
{"Sectigo 'Mammoth2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1728925200000, // 2024-10-14T17:00:00Z
|
1728925200000, // 2024-10-14T17:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -291,7 +297,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x9b\x50\x28\xe2\x9e\x58\xa5\xa5\xfa\xf9\xe3\xfa\x15\x25\xe3\x14\x13\x32"
|
"\x9b\x50\x28\xe2\x9e\x58\xa5\xa5\xfa\xf9\xe3\xfa\x15\x25\xe3\x14\x13\x32"
|
||||||
"\xc4",
|
"\xc4",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Mammoth2026h2'", CTLogState::Admissible,
|
{"Sectigo 'Mammoth2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1728925200000, // 2024-10-14T17:00:00Z
|
1728925200000, // 2024-10-14T17:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -301,7 +307,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xff\xc2\x97\x71\xe5\x7e\x27\xf5\x72\xb1\x8f\x24\x27\x57\x0a\x0d\x74\xc0"
|
"\xff\xc2\x97\x71\xe5\x7e\x27\xf5\x72\xb1\x8f\x24\x27\x57\x0a\x0d\x74\xc0"
|
||||||
"\xb6",
|
"\xb6",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Sabre2026h1'", CTLogState::Admissible,
|
{"Sectigo 'Sabre2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1728925200000, // 2024-10-14T17:00:00Z
|
1728925200000, // 2024-10-14T17:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -311,7 +317,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x46\x67\x51\xf0\xde\xb6\xc9\x9e\xaa\xe2\x80\x6d\xce\x25\x81\x34\xd7\x6a"
|
"\x46\x67\x51\xf0\xde\xb6\xc9\x9e\xaa\xe2\x80\x6d\xce\x25\x81\x34\xd7\x6a"
|
||||||
"\x60",
|
"\x60",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Sabre2026h2'", CTLogState::Admissible,
|
{"Sectigo 'Sabre2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1728925200000, // 2024-10-14T17:00:00Z
|
1728925200000, // 2024-10-14T17:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -321,7 +327,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x65\x35\x63\xf0\x49\xbe\x72\xd1\xaa\x9d\xaf\x7d\x08\xc4\xb4\x8d\x59\x3d"
|
"\x65\x35\x63\xf0\x49\xbe\x72\xd1\xaa\x9d\xaf\x7d\x08\xc4\xb4\x8d\x59\x3d"
|
||||||
"\x73",
|
"\x73",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Elephant2025h2'", CTLogState::Admissible,
|
{"Sectigo 'Elephant2025h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1747100000000, // 2025-05-13T01:33:20Z
|
1747100000000, // 2025-05-13T01:33:20Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -331,7 +337,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xc3\xc4\x42\xc1\x5b\x0a\x85\x16\xce\xa8\xc1\x0e\xc5\x6e\x10\xda\x9e\x0a"
|
"\xc3\xc4\x42\xc1\x5b\x0a\x85\x16\xce\xa8\xc1\x0e\xc5\x6e\x10\xda\x9e\x0a"
|
||||||
"\x42",
|
"\x42",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Elephant2026h1'", CTLogState::Admissible,
|
{"Sectigo 'Elephant2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1747100000000, // 2025-05-13T01:33:20Z
|
1747100000000, // 2025-05-13T01:33:20Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -341,7 +347,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xc9\x65\x87\xe0\xd4\x7f\x0c\x22\x5a\xd9\xb0\x2e\x98\x7a\xd7\x25\xd0\x1c"
|
"\xc9\x65\x87\xe0\xd4\x7f\x0c\x22\x5a\xd9\xb0\x2e\x98\x7a\xd7\x25\xd0\x1c"
|
||||||
"\x69",
|
"\x69",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Elephant2026h2'", CTLogState::Admissible,
|
{"Sectigo 'Elephant2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1747100000000, // 2025-05-13T01:33:20Z
|
1747100000000, // 2025-05-13T01:33:20Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -351,7 +357,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x09\xfc\xdd\x0f\xbc\x5c\x56\x39\x90\x62\x96\xed\x35\x48\x71\x44\xc4\x6d"
|
"\x09\xfc\xdd\x0f\xbc\x5c\x56\x39\x90\x62\x96\xed\x35\x48\x71\x44\xc4\x6d"
|
||||||
"\x98",
|
"\x98",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Elephant2027h1'", CTLogState::Admissible,
|
{"Sectigo 'Elephant2027h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1747100000000, // 2025-05-13T01:33:20Z
|
1747100000000, // 2025-05-13T01:33:20Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -361,7 +367,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xa0\x6a\xda\x7f\xb0\x64\xcc\xa6\x5f\xec\xf0\xbc\x81\x80\x12\x73\x0d\xb0"
|
"\xa0\x6a\xda\x7f\xb0\x64\xcc\xa6\x5f\xec\xf0\xbc\x81\x80\x12\x73\x0d\xb0"
|
||||||
"\xa0",
|
"\xa0",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Elephant2027h2'", CTLogState::Admissible,
|
{"Sectigo 'Elephant2027h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1747100000000, // 2025-05-13T01:33:20Z
|
1747100000000, // 2025-05-13T01:33:20Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -371,7 +377,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x1e\xdc\x8a\xec\x20\x61\x7e\x52\x25\x32\x4e\xd3\xd9\x0a\xe7\xe3\x0f\xed"
|
"\x1e\xdc\x8a\xec\x20\x61\x7e\x52\x25\x32\x4e\xd3\xd9\x0a\xe7\xe3\x0f\xed"
|
||||||
"\xf2",
|
"\xf2",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Tiger2025h2'", CTLogState::Admissible,
|
{"Sectigo 'Tiger2025h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1752066000000, // 2025-07-09T13:00:00Z
|
1752066000000, // 2025-07-09T13:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -381,7 +387,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xd8\xa1\x24\x59\x2f\xb8\x4f\xbf\xdb\x60\xe5\xef\xe1\xd0\xcd\xcf\x3a\xc4"
|
"\xd8\xa1\x24\x59\x2f\xb8\x4f\xbf\xdb\x60\xe5\xef\xe1\xd0\xcd\xcf\x3a\xc4"
|
||||||
"\xc6",
|
"\xc6",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Tiger2026h1'", CTLogState::Admissible,
|
{"Sectigo 'Tiger2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1752066000000, // 2025-07-09T13:00:00Z
|
1752066000000, // 2025-07-09T13:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -391,7 +397,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xef\xf5\xd0\x63\x03\x85\xb7\xd1\x5e\x6f\xc4\xf0\x41\x6f\xa6\xa9\x73\x79"
|
"\xef\xf5\xd0\x63\x03\x85\xb7\xd1\x5e\x6f\xc4\xf0\x41\x6f\xa6\xa9\x73\x79"
|
||||||
"\xc6",
|
"\xc6",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Tiger2026h2'", CTLogState::Admissible,
|
{"Sectigo 'Tiger2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1752066000000, // 2025-07-09T13:00:00Z
|
1752066000000, // 2025-07-09T13:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -401,7 +407,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x08\x44\xb5\x10\xbd\x41\xfb\x60\x44\x0b\xe3\xf9\x6d\x47\xf0\x17\x8e\x25"
|
"\x08\x44\xb5\x10\xbd\x41\xfb\x60\x44\x0b\xe3\xf9\x6d\x47\xf0\x17\x8e\x25"
|
||||||
"\x9c",
|
"\x9c",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Tiger2027h1'", CTLogState::Admissible,
|
{"Sectigo 'Tiger2027h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1752066000000, // 2025-07-09T13:00:00Z
|
1752066000000, // 2025-07-09T13:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -411,7 +417,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xdc\xd8\x27\x5c\x35\xf0\x9b\x22\x5c\x17\x04\x58\x81\x53\x81\x32\x16\x98"
|
"\xdc\xd8\x27\x5c\x35\xf0\x9b\x22\x5c\x17\x04\x58\x81\x53\x81\x32\x16\x98"
|
||||||
"\x84",
|
"\x84",
|
||||||
91},
|
91},
|
||||||
{"Sectigo 'Tiger2027h2'", CTLogState::Admissible,
|
{"Sectigo 'Tiger2027h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1752066000000, // 2025-07-09T13:00:00Z
|
1752066000000, // 2025-07-09T13:00:00Z
|
||||||
3, // operated by Sectigo
|
3, // operated by Sectigo
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -421,7 +427,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xa3\x4f\x6b\xa3\x37\xdd\xaa\x18\xde\x8a\x12\x25\xdb\x9c\xbd\x03\x72\x61"
|
"\xa3\x4f\x6b\xa3\x37\xdd\xaa\x18\xde\x8a\x12\x25\xdb\x9c\xbd\x03\x72\x61"
|
||||||
"\xc9",
|
"\xc9",
|
||||||
91},
|
91},
|
||||||
{"Let's Encrypt 'Oak2025h1'", CTLogState::Admissible,
|
{"Let's Encrypt 'Oak2025h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
4, // operated by Let's Encrypt
|
4, // operated by Let's Encrypt
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -431,7 +437,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xf9\x3c\x58\x54\x5b\x37\x10\xb1\xab\xd8\x83\xfb\x84\xf1\x95\x3f\x2e\x2f"
|
"\xf9\x3c\x58\x54\x5b\x37\x10\xb1\xab\xd8\x83\xfb\x84\xf1\x95\x3f\x2e\x2f"
|
||||||
"\x1c",
|
"\x1c",
|
||||||
91},
|
91},
|
||||||
{"Let's Encrypt 'Oak2025h2'", CTLogState::Admissible,
|
{"Let's Encrypt 'Oak2025h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
4, // operated by Let's Encrypt
|
4, // operated by Let's Encrypt
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -441,7 +447,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xc9\xd7\x3d\xbb\xc1\xf7\x71\x86\x69\xf4\xb3\x5f\x90\x09\xaa\xae\xbd\x8d"
|
"\xc9\xd7\x3d\xbb\xc1\xf7\x71\x86\x69\xf4\xb3\x5f\x90\x09\xaa\xae\xbd\x8d"
|
||||||
"\xa9",
|
"\xa9",
|
||||||
91},
|
91},
|
||||||
{"Let's Encrypt 'Oak2026h1'", CTLogState::Admissible,
|
{"Let's Encrypt 'Oak2026h1'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1730678400000, // 2024-11-04T00:00:00Z
|
1730678400000, // 2024-11-04T00:00:00Z
|
||||||
4, // operated by Let's Encrypt
|
4, // operated by Let's Encrypt
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -451,7 +457,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x48\x90\x23\x40\xde\x7a\x4d\x89\x32\xfb\xd7\x0a\xeb\x5e\x8c\xa2\xf1\xf6"
|
"\x48\x90\x23\x40\xde\x7a\x4d\x89\x32\xfb\xd7\x0a\xeb\x5e\x8c\xa2\xf1\xf6"
|
||||||
"\x49",
|
"\x49",
|
||||||
91},
|
91},
|
||||||
{"Let's Encrypt 'Oak2026h2'", CTLogState::Admissible,
|
{"Let's Encrypt 'Oak2026h2'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1730678400000, // 2024-11-04T00:00:00Z
|
1730678400000, // 2024-11-04T00:00:00Z
|
||||||
4, // operated by Let's Encrypt
|
4, // operated by Let's Encrypt
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -461,7 +467,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xf4\xfc\x5c\xa9\x8c\x5f\xfb\x0d\x60\xe4\x2c\x0f\x16\xec\x2a\xb2\x6d\xeb"
|
"\xf4\xfc\x5c\xa9\x8c\x5f\xfb\x0d\x60\xe4\x2c\x0f\x16\xec\x2a\xb2\x6d\xeb"
|
||||||
"\x15",
|
"\x15",
|
||||||
91},
|
91},
|
||||||
{"TrustAsia Log2025a", CTLogState::Admissible,
|
{"TrustAsia Log2025a", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
5, // operated by TrustAsia
|
5, // operated by TrustAsia
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -471,7 +477,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x90\x58\xba\x22\xd5\xf9\xf5\x69\x54\xb7\xa8\x94\x4e\x32\x09\xae\x26\x11"
|
"\x90\x58\xba\x22\xd5\xf9\xf5\x69\x54\xb7\xa8\x94\x4e\x32\x09\xae\x26\x11"
|
||||||
"\x4d",
|
"\x4d",
|
||||||
91},
|
91},
|
||||||
{"TrustAsia Log2025b", CTLogState::Admissible,
|
{"TrustAsia Log2025b", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1701000000000, // 2023-11-26T12:00:00Z
|
1701000000000, // 2023-11-26T12:00:00Z
|
||||||
5, // operated by TrustAsia
|
5, // operated by TrustAsia
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -481,7 +487,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xbd\x2f\xa9\xcf\xe8\x7b\x5e\xe1\x4b\x60\xe5\x38\x43\x60\x97\xc1\x5b\x2f"
|
"\xbd\x2f\xa9\xcf\xe8\x7b\x5e\xe1\x4b\x60\xe5\x38\x43\x60\x97\xc1\x5b\x2f"
|
||||||
"\x65",
|
"\x65",
|
||||||
91},
|
91},
|
||||||
{"TrustAsia 'log2026a'", CTLogState::Admissible,
|
{"TrustAsia 'log2026a'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1726790400000, // 2024-09-20T00:00:00Z
|
1726790400000, // 2024-09-20T00:00:00Z
|
||||||
5, // operated by TrustAsia
|
5, // operated by TrustAsia
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -491,7 +497,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x89\x17\xe8\x5b\x2e\xc5\xac\x00\x05\xc9\x76\x37\x45\x97\x03\x15\xff\x60"
|
"\x89\x17\xe8\x5b\x2e\xc5\xac\x00\x05\xc9\x76\x37\x45\x97\x03\x15\xff\x60"
|
||||||
"\x59",
|
"\x59",
|
||||||
91},
|
91},
|
||||||
{"TrustAsia 'log2026b'", CTLogState::Admissible,
|
{"TrustAsia 'log2026b'", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1726790400000, // 2024-09-20T00:00:00Z
|
1726790400000, // 2024-09-20T00:00:00Z
|
||||||
5, // operated by TrustAsia
|
5, // operated by TrustAsia
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -501,7 +507,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x9d\x7d\x05\x53\xc7\x9e\x94\xea\x9b\x57\x46\xbf\x4f\xa4\x7e\xfb\xdf\xfa"
|
"\x9d\x7d\x05\x53\xc7\x9e\x94\xea\x9b\x57\x46\xbf\x4f\xa4\x7e\xfb\xdf\xfa"
|
||||||
"\x85",
|
"\x85",
|
||||||
91},
|
91},
|
||||||
{"Bogus placeholder log to unbreak misbehaving CT libraries", CTLogState::Retired,
|
{"Bogus placeholder log to unbreak misbehaving CT libraries", CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
1750489200000, // 2025-06-21T07:00:00Z
|
1750489200000, // 2025-06-21T07:00:00Z
|
||||||
6, // operated by Geomys
|
6, // operated by Geomys
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -511,8 +517,38 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\x75\xe3\x66\x75\xa9\x59\x70\x2d\xe2\x5a\x8b\xc0\x7c\x0a\x6f\x5d\x2d\xf7"
|
"\x75\xe3\x66\x75\xa9\x59\x70\x2d\xe2\x5a\x8b\xc0\x7c\x0a\x6f\x5d\x2d\xf7"
|
||||||
"\x37",
|
"\x37",
|
||||||
91},
|
91},
|
||||||
|
{"Geomys 'Tuscolo2025h2'", CTLogState::Admissible, CTLogFormat::Tiled,
|
||||||
|
1749782400000, // 2025-06-13T02:40:00Z
|
||||||
|
6, // operated by Geomys
|
||||||
|
"\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\x2b\xd7\x78\x18\x6b\x73\x6e\x4c\x30"
|
||||||
|
"\xb1\x8a\x44\xb6\xf9\xd4\xf4\xa2\xa0\x66\xbe\xbb\x32\xc1\xa5\x07\xb9\xa7"
|
||||||
|
"\x17\xc0\xd6\xf5\xb1\xe7\x9e\x01\xf3\x3f\x35\xcf\x6d\xda\x3b\x9f\xe1\x72"
|
||||||
|
"\x0b\x04\x83\x62\xa1\x07\x6d\xa9\x75\x67\x40\x82\x57\x26\x43\xeb\x04\x3f"
|
||||||
|
"\xa3",
|
||||||
|
91},
|
||||||
|
{"Geomys 'Tuscolo2026h1'", CTLogState::Admissible, CTLogFormat::Tiled,
|
||||||
|
1749782400000, // 2025-06-13T02:40:00Z
|
||||||
|
6, // operated by Geomys
|
||||||
|
"\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\x7e\x5c\x73\x32\x0d\x80\x8e\x38\x3b"
|
||||||
|
"\x87\x5f\x99\x22\xf4\x3d\x2d\x5e\xb2\x16\xf7\x63\xea\xe4\x62\xf5\x86\xef"
|
||||||
|
"\xb5\x19\xd2\x0a\x04\xb6\x49\xa9\xa4\x1f\x9e\x96\x70\xf4\x5a\x05\x34\x58"
|
||||||
|
"\x01\x13\xc3\x22\xbe\x49\xc0\xba\xa0\x24\x05\x40\xfc\xdb\xc3\xc5\xd2\x57"
|
||||||
|
"\x3b",
|
||||||
|
91},
|
||||||
|
{"Geomys 'Tuscolo2026h2'", CTLogState::Admissible, CTLogFormat::Tiled,
|
||||||
|
1749782400000, // 2025-06-13T02:40:00Z
|
||||||
|
6, // operated by Geomys
|
||||||
|
"\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\x68\x0e\x8f\xd2\x2e\xc9\x4e\xc7\x7d"
|
||||||
|
"\x5d\xfc\xc5\xd7\xfe\xfa\x6a\xf4\x56\x03\x75\xd7\x23\x83\x52\xb6\xc1\x4e"
|
||||||
|
"\xfd\xa1\x6d\x06\x9e\x92\x63\xba\x25\x0c\x43\x22\x3d\x21\x52\xc4\x6c\xc5"
|
||||||
|
"\x42\x32\x80\xd6\xbf\x6f\x80\x6f\xe8\x15\x0c\x2e\xae\x55\x8c\xcb\xd1\x50"
|
||||||
|
"\x37",
|
||||||
|
91},
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{"Mozilla Test RSA Log 1", CTLogState::Admissible,
|
{"Mozilla Test RSA Log 1", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1721666666000, // 2024-07-22T16:44:26Z
|
1721666666000, // 2024-07-22T16:44:26Z
|
||||||
7, // operated by Mozilla Test Org 1
|
7, // operated by Mozilla Test Org 1
|
||||||
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
|
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
|
||||||
@@ -535,7 +571,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
294},
|
294},
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{"Mozilla Test EC Log", CTLogState::Admissible,
|
{"Mozilla Test EC Log", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1721666666000, // 2024-07-22T16:44:26Z
|
1721666666000, // 2024-07-22T16:44:26Z
|
||||||
7, // operated by Mozilla Test Org 1
|
7, // operated by Mozilla Test Org 1
|
||||||
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48"
|
||||||
@@ -547,7 +583,7 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
91},
|
91},
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{"Mozilla Test RSA Log 2", CTLogState::Admissible,
|
{"Mozilla Test RSA Log 2", CTLogState::Admissible, CTLogFormat::RFC6962,
|
||||||
1721666666000, // 2024-07-22T16:44:26Z
|
1721666666000, // 2024-07-22T16:44:26Z
|
||||||
8, // operated by Mozilla Test Org 2
|
8, // operated by Mozilla Test Org 2
|
||||||
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
|
"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05"
|
||||||
@@ -569,6 +605,29 @@ const CTLogInfo kCTLogList[] = {
|
|||||||
"\xbb\x02\x03\x01\x00\x01",
|
"\xbb\x02\x03\x01\x00\x01",
|
||||||
294},
|
294},
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
#ifdef DEBUG
|
||||||
|
{"Mozilla Test RSA Log 4", CTLogState::Admissible, CTLogFormat::Tiled,
|
||||||
|
1750853366000, // 2025-06-25T12:09:26Z
|
||||||
|
9, // operated by Mozilla Test Org 3
|
||||||
|
"\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\xb5\x49\x89"
|
||||||
|
"\x5c\x9d\x00\x10\x8d\x11\xa1\xf9\x9f\x87\xa9\xe3\xd1\xa5\xdb\x5d\xfa\xec"
|
||||||
|
"\xf1\x88\xda\x57\xbf\x64\x13\x68\x8f\x2c\xe4\x72\x2c\xff\x10\x90\x38\xc1"
|
||||||
|
"\x74\x02\xc9\x3a\x2a\x47\x3d\xbd\x28\x6a\xed\x3f\xdc\xd3\x63\xcf\x5a\x29"
|
||||||
|
"\x14\x77\x01\xbd\xd8\x18\xd7\x61\x5b\xf9\x35\x6b\xd5\xd3\xc8\x33\x6a\xaa"
|
||||||
|
"\x8c\x09\x71\x36\x8a\x06\xc3\xcd\x44\x61\xb9\x3e\x51\x42\x4e\x17\x44\xbb"
|
||||||
|
"\x2e\xaa\xd4\x6a\xab\x38\xce\x19\x68\x21\x96\x1f\x87\x71\x4a\x16\x63\x69"
|
||||||
|
"\x3f\x09\x76\x1c\xdf\x4d\x6b\xa1\x25\xea\xce\xc7\xbe\x27\x0d\x38\x8f\x78"
|
||||||
|
"\x9f\x6c\xdf\x78\xae\x31\x44\xed\x28\xc4\x5e\x79\x29\x38\x63\xa7\xa2\x2a"
|
||||||
|
"\x48\x98\x0a\x36\xa4\x0e\x72\xd5\x79\xc9\xb9\x25\xdf\xf8\xc7\x93\x36\x2f"
|
||||||
|
"\xfd\x68\x97\xa7\xc1\x75\x4c\x5e\x97\xc9\x67\xc3\xea\xdd\x1a\xae\x8a\xa2"
|
||||||
|
"\xcc\xce\x34\x8a\x01\x69\xb8\x0e\x28\xa2\xd7\x0c\x1a\x96\x0c\x6f\x33\x5f"
|
||||||
|
"\x2d\xa0\x9b\x9b\x64\x3f\x5a\xbf\xba\x49\xe8\xaa\xa9\x81\xe9\x60\xe2\x7d"
|
||||||
|
"\x87\x48\x0b\xdd\x55\xdd\x94\x17\xfa\x18\x50\x9f\xbb\x55\x4c\xcf\x81\xa4"
|
||||||
|
"\x39\x7e\x8b\xa8\x12\x8a\x34\xbd\xf2\x78\x65\xc1\x89\xe5\x73\x4f\xb2\x29"
|
||||||
|
"\x05\x02\x03\x01\x00\x01",
|
||||||
|
294},
|
||||||
|
#endif // DEBUG
|
||||||
};
|
};
|
||||||
|
|
||||||
const CTLogOperatorInfo kCTLogOperatorList[] = {
|
const CTLogOperatorInfo kCTLogOperatorList[] = {
|
||||||
@@ -585,6 +644,9 @@ const CTLogOperatorInfo kCTLogOperatorList[] = {
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
{"Mozilla Test Org 2", 8},
|
{"Mozilla Test Org 2", 8},
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
#ifdef DEBUG
|
||||||
|
{"Mozilla Test Org 3", 9},
|
||||||
|
#endif // DEBUG
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::ct
|
} // namespace mozilla::ct
|
||||||
|
|||||||
@@ -114,10 +114,11 @@ class SignatureParamsTrustDomain final : public TrustDomain {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CTLogVerifier::CTLogVerifier(CTLogOperatorId operatorId, CTLogState state,
|
CTLogVerifier::CTLogVerifier(CTLogOperatorId operatorId, CTLogState state,
|
||||||
uint64_t timestamp)
|
CTLogFormat format, uint64_t timestamp)
|
||||||
: mSignatureAlgorithm(DigitallySigned::SignatureAlgorithm::Anonymous),
|
: mSignatureAlgorithm(DigitallySigned::SignatureAlgorithm::Anonymous),
|
||||||
mOperatorId(operatorId),
|
mOperatorId(operatorId),
|
||||||
mState(state),
|
mState(state),
|
||||||
|
mFormat(format),
|
||||||
mTimestamp(timestamp) {}
|
mTimestamp(timestamp) {}
|
||||||
|
|
||||||
pkix::Result CTLogVerifier::Init(Input subjectPublicKeyInfo) {
|
pkix::Result CTLogVerifier::Init(Input subjectPublicKeyInfo) {
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ class CTLogVerifier {
|
|||||||
public:
|
public:
|
||||||
// |operatorId| The numeric ID of the log operator.
|
// |operatorId| The numeric ID of the log operator.
|
||||||
// |logState| "Qualified", "Usable", "ReadOnly", or "Retired".
|
// |logState| "Qualified", "Usable", "ReadOnly", or "Retired".
|
||||||
|
// |logFormat| "RFC6962" or "Tiled"
|
||||||
// |timestamp| timestamp associated with logState.
|
// |timestamp| timestamp associated with logState.
|
||||||
CTLogVerifier(CTLogOperatorId operatorId, CTLogState logState,
|
CTLogVerifier(CTLogOperatorId operatorId, CTLogState logState,
|
||||||
uint64_t timestamp);
|
CTLogFormat logFormat, uint64_t timestamp);
|
||||||
|
|
||||||
// Initializes the verifier with the given subjectPublicKeyInfo.
|
// Initializes the verifier with the given subjectPublicKeyInfo.
|
||||||
// |subjectPublicKeyInfo| is a DER-encoded SubjectPublicKeyInfo.
|
// |subjectPublicKeyInfo| is a DER-encoded SubjectPublicKeyInfo.
|
||||||
@@ -46,6 +47,7 @@ class CTLogVerifier {
|
|||||||
|
|
||||||
CTLogOperatorId operatorId() const { return mOperatorId; }
|
CTLogOperatorId operatorId() const { return mOperatorId; }
|
||||||
CTLogState state() const { return mState; }
|
CTLogState state() const { return mState; }
|
||||||
|
CTLogFormat format() const { return mFormat; }
|
||||||
uint64_t timestamp() const { return mTimestamp; }
|
uint64_t timestamp() const { return mTimestamp; }
|
||||||
|
|
||||||
// Verifies that |sct| contains a valid signature for |entry|.
|
// Verifies that |sct| contains a valid signature for |entry|.
|
||||||
@@ -74,6 +76,7 @@ class CTLogVerifier {
|
|||||||
DigitallySigned::SignatureAlgorithm mSignatureAlgorithm;
|
DigitallySigned::SignatureAlgorithm mSignatureAlgorithm;
|
||||||
CTLogOperatorId mOperatorId;
|
CTLogOperatorId mOperatorId;
|
||||||
CTLogState mState;
|
CTLogState mState;
|
||||||
|
CTLogFormat mFormat;
|
||||||
uint64_t mTimestamp;
|
uint64_t mTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,13 @@ bool LogWasQualifiedForSct(const VerifiedSCT& verifiedSct,
|
|||||||
// lifetime of the certificate. If the certificate lifetime is less than or
|
// lifetime of the certificate. If the certificate lifetime is less than or
|
||||||
// equal to 180 days, N is 2. Otherwise, N is 3.
|
// equal to 180 days, N is 2. Otherwise, N is 3.
|
||||||
// Among these SCTs, at least two must be issued from distinct log operators.
|
// Among these SCTs, at least two must be issued from distinct log operators.
|
||||||
|
// Additionally, at least one must be issued from an RFC6962 log.
|
||||||
CTPolicyCompliance EmbeddedSCTsCompliant(const VerifiedSCTList& verifiedScts,
|
CTPolicyCompliance EmbeddedSCTsCompliant(const VerifiedSCTList& verifiedScts,
|
||||||
uint64_t certIssuanceTime,
|
uint64_t certIssuanceTime,
|
||||||
Duration certLifetime) {
|
Duration certLifetime) {
|
||||||
size_t admissibleCount = 0;
|
size_t admissibleCount = 0;
|
||||||
size_t admissibleOrRetiredCount = 0;
|
size_t admissibleOrRetiredCount = 0;
|
||||||
|
size_t rfc6962Count = 0;
|
||||||
std::set<CTLogOperatorId> logOperators;
|
std::set<CTLogOperatorId> logOperators;
|
||||||
std::set<Buffer> logIds;
|
std::set<Buffer> logIds;
|
||||||
for (const auto& verifiedSct : verifiedScts) {
|
for (const auto& verifiedSct : verifiedScts) {
|
||||||
@@ -90,6 +92,14 @@ CTPolicyCompliance EmbeddedSCTsCompliant(const VerifiedSCTList& verifiedScts,
|
|||||||
!LogWasQualifiedForSct(verifiedSct, certIssuanceTime)) {
|
!LogWasQualifiedForSct(verifiedSct, certIssuanceTime)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// SCTs from tiled logs "MUST" have a valid leaf index extension.
|
||||||
|
if (verifiedSct.logFormat == CTLogFormat::Tiled &&
|
||||||
|
verifiedSct.sct.leafIndex.isNothing()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (verifiedSct.logFormat == CTLogFormat::RFC6962) {
|
||||||
|
rfc6962Count++;
|
||||||
|
}
|
||||||
// Note that a single SCT can count for both the "from a log that was
|
// Note that a single SCT can count for both the "from a log that was
|
||||||
// admissible" case and the "from a log that was admissible or retired"
|
// admissible" case and the "from a log that was admissible or retired"
|
||||||
// case.
|
// case.
|
||||||
@@ -104,7 +114,8 @@ CTPolicyCompliance EmbeddedSCTsCompliant(const VerifiedSCTList& verifiedScts,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t requiredEmbeddedScts = GetRequiredEmbeddedSctsCount(certLifetime);
|
size_t requiredEmbeddedScts = GetRequiredEmbeddedSctsCount(certLifetime);
|
||||||
if (admissibleCount < 1 || admissibleOrRetiredCount < requiredEmbeddedScts) {
|
if (admissibleCount < 1 || admissibleOrRetiredCount < requiredEmbeddedScts ||
|
||||||
|
rfc6962Count < 1) {
|
||||||
return CTPolicyCompliance::NotEnoughScts;
|
return CTPolicyCompliance::NotEnoughScts;
|
||||||
}
|
}
|
||||||
if (logIds.size() < requiredEmbeddedScts || logOperators.size() < 2) {
|
if (logIds.size() < requiredEmbeddedScts || logOperators.size() < 2) {
|
||||||
@@ -117,10 +128,12 @@ CTPolicyCompliance EmbeddedSCTsCompliant(const VerifiedSCTList& verifiedScts,
|
|||||||
// or OCSP response):
|
// or OCSP response):
|
||||||
// There must be at least two SCTs from logs that were Admissible (i.e.
|
// There must be at least two SCTs from logs that were Admissible (i.e.
|
||||||
// Qualified, Usable, or ReadOnly) at the time of the check. Among these SCTs,
|
// Qualified, Usable, or ReadOnly) at the time of the check. Among these SCTs,
|
||||||
// at least two must be issued from distinct log operators.
|
// at least two must be issued from distinct log operators. Additionally, at
|
||||||
|
// least one must be issued from an RFC6962 log.
|
||||||
CTPolicyCompliance NonEmbeddedSCTsCompliant(
|
CTPolicyCompliance NonEmbeddedSCTsCompliant(
|
||||||
const VerifiedSCTList& verifiedScts) {
|
const VerifiedSCTList& verifiedScts) {
|
||||||
size_t admissibleCount = 0;
|
size_t admissibleCount = 0;
|
||||||
|
size_t rfc6962Count = 0;
|
||||||
std::set<CTLogOperatorId> logOperators;
|
std::set<CTLogOperatorId> logOperators;
|
||||||
std::set<Buffer> logIds;
|
std::set<Buffer> logIds;
|
||||||
for (const auto& verifiedSct : verifiedScts) {
|
for (const auto& verifiedSct : verifiedScts) {
|
||||||
@@ -130,12 +143,20 @@ CTPolicyCompliance NonEmbeddedSCTsCompliant(
|
|||||||
if (verifiedSct.logState != CTLogState::Admissible) {
|
if (verifiedSct.logState != CTLogState::Admissible) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// SCTs from tiled logs "MUST" have a valid leaf index extension.
|
||||||
|
if (verifiedSct.logFormat == CTLogFormat::Tiled &&
|
||||||
|
verifiedSct.sct.leafIndex.isNothing()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
admissibleCount++;
|
admissibleCount++;
|
||||||
|
if (verifiedSct.logFormat == CTLogFormat::RFC6962) {
|
||||||
|
rfc6962Count++;
|
||||||
|
}
|
||||||
logIds.insert(verifiedSct.sct.logId);
|
logIds.insert(verifiedSct.sct.logId);
|
||||||
logOperators.insert(verifiedSct.logOperatorId);
|
logOperators.insert(verifiedSct.logOperatorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (admissibleCount < 2) {
|
if (admissibleCount < 2 || rfc6962Count < 1) {
|
||||||
return CTPolicyCompliance::NotEnoughScts;
|
return CTPolicyCompliance::NotEnoughScts;
|
||||||
}
|
}
|
||||||
if (logIds.size() < 2 || logOperators.size() < 2) {
|
if (logIds.size() < 2 || logOperators.size() < 2) {
|
||||||
|
|||||||
@@ -360,6 +360,11 @@ Result DecodeSignedCertificateTimestamp(Reader& reader,
|
|||||||
InputToBuffer(extensions, result.extensions);
|
InputToBuffer(extensions, result.extensions);
|
||||||
result.timestamp = timestamp;
|
result.timestamp = timestamp;
|
||||||
|
|
||||||
|
rv = result.DecodeExtensions();
|
||||||
|
if (rv != Success) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
output = std::move(result);
|
output = std::move(result);
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ namespace ct {
|
|||||||
|
|
||||||
VerifiedSCT::VerifiedSCT(SignedCertificateTimestamp&& sct, SCTOrigin origin,
|
VerifiedSCT::VerifiedSCT(SignedCertificateTimestamp&& sct, SCTOrigin origin,
|
||||||
CTLogOperatorId logOperatorId, CTLogState logState,
|
CTLogOperatorId logOperatorId, CTLogState logState,
|
||||||
uint64_t logTimestamp)
|
CTLogFormat logFormat, uint64_t logTimestamp)
|
||||||
: sct(std::move(sct)),
|
: sct(std::move(sct)),
|
||||||
origin(origin),
|
origin(origin),
|
||||||
logOperatorId(logOperatorId),
|
logOperatorId(logOperatorId),
|
||||||
logState(logState),
|
logState(logState),
|
||||||
|
logFormat(logFormat),
|
||||||
logTimestamp(logTimestamp) {}
|
logTimestamp(logTimestamp) {}
|
||||||
|
|
||||||
void CTVerifyResult::Reset() {
|
void CTVerifyResult::Reset() {
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ enum class SCTOrigin {
|
|||||||
struct VerifiedSCT {
|
struct VerifiedSCT {
|
||||||
VerifiedSCT(SignedCertificateTimestamp&& sct, SCTOrigin origin,
|
VerifiedSCT(SignedCertificateTimestamp&& sct, SCTOrigin origin,
|
||||||
CTLogOperatorId logOperatorId, CTLogState logState,
|
CTLogOperatorId logOperatorId, CTLogState logState,
|
||||||
uint64_t logTimestamp);
|
CTLogFormat logFormat, uint64_t logTimestamp);
|
||||||
|
|
||||||
// The original SCT.
|
// The original SCT.
|
||||||
SignedCertificateTimestamp sct;
|
SignedCertificateTimestamp sct;
|
||||||
SCTOrigin origin;
|
SCTOrigin origin;
|
||||||
CTLogOperatorId logOperatorId;
|
CTLogOperatorId logOperatorId;
|
||||||
CTLogState logState;
|
CTLogState logState;
|
||||||
|
CTLogFormat logFormat;
|
||||||
uint64_t logTimestamp;
|
uint64_t logTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ pkix::Result MultiLogCTVerifier::VerifySingleSCT(
|
|||||||
}
|
}
|
||||||
|
|
||||||
VerifiedSCT verifiedSct(std::move(sct), origin, matchingLog->operatorId(),
|
VerifiedSCT verifiedSct(std::move(sct), origin, matchingLog->operatorId(),
|
||||||
matchingLog->state(), matchingLog->timestamp());
|
matchingLog->state(), matchingLog->format(),
|
||||||
|
matchingLog->timestamp());
|
||||||
result.verifiedScts.push_back(std::move(verifiedSct));
|
result.verifiedScts.push_back(std::move(verifiedSct));
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,72 @@
|
|||||||
|
|
||||||
#include "SignedCertificateTimestamp.h"
|
#include "SignedCertificateTimestamp.h"
|
||||||
|
|
||||||
|
#include "CTUtils.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ct {
|
namespace ct {
|
||||||
|
|
||||||
|
pkix::Result SignedCertificateTimestamp::DecodeExtensions() {
|
||||||
|
if (extensions.empty()) {
|
||||||
|
return pkix::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `extensions` is a sequence of Extension:
|
||||||
|
// struct {
|
||||||
|
// ExtensionType extension_type;
|
||||||
|
// opaque extension_data<0..2^16-1>;
|
||||||
|
// } Extension;
|
||||||
|
const size_t kExtensionDataLengthBytes = 2;
|
||||||
|
// Currently, the only supported extension type is `leaf_index`. Others are
|
||||||
|
// ignored.
|
||||||
|
// enum {
|
||||||
|
// leaf_index(0), (255)
|
||||||
|
// } ExtensionType;
|
||||||
|
const size_t kExtensionTypeLength = 1;
|
||||||
|
const uint8_t kExtensionTypeLeafIndex = 0;
|
||||||
|
|
||||||
|
pkix::Input input;
|
||||||
|
pkix::Result rv = input.Init(extensions.data(), extensions.size());
|
||||||
|
if (rv != pkix::Success) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
pkix::Reader reader(input);
|
||||||
|
while (!reader.AtEnd()) {
|
||||||
|
uint8_t extensionType;
|
||||||
|
rv = ReadUint<kExtensionTypeLength>(reader, extensionType);
|
||||||
|
if (rv != pkix::Success) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
pkix::Input extensionData;
|
||||||
|
rv = ReadVariableBytes<kExtensionDataLengthBytes>(reader, extensionData);
|
||||||
|
if (rv != pkix::Success) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (extensionType == kExtensionTypeLeafIndex) {
|
||||||
|
// Duplicate extensions are not allowed.
|
||||||
|
if (leafIndex.isSome()) {
|
||||||
|
return pkix::Result::ERROR_EXTENSION_VALUE_INVALID;
|
||||||
|
}
|
||||||
|
// A leaf index is a big-endian, unsigned 40-bit value. In other words,
|
||||||
|
// it is 5 8-bit bytes, like so:
|
||||||
|
// uint8 uint40[5];
|
||||||
|
// uint40 LeafIndex;
|
||||||
|
const size_t kLeafIndexLength = 5;
|
||||||
|
uint64_t leafIndexValue;
|
||||||
|
pkix::Reader leafIndexReader(extensionData);
|
||||||
|
rv = ReadUint<kLeafIndexLength>(leafIndexReader, leafIndexValue);
|
||||||
|
if (rv != pkix::Success) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (!leafIndexReader.AtEnd()) {
|
||||||
|
return pkix::Result::ERROR_EXTENSION_VALUE_INVALID;
|
||||||
|
}
|
||||||
|
leafIndex.emplace(leafIndexValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pkix::Success;
|
||||||
|
}
|
||||||
|
|
||||||
void LogEntry::Reset() {
|
void LogEntry::Reset() {
|
||||||
type = LogEntry::Type::X509;
|
type = LogEntry::Type::X509;
|
||||||
leafCertificate.clear();
|
leafCertificate.clear();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#define SignedCertificateTimestamp_h
|
#define SignedCertificateTimestamp_h
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozpkix/Input.h"
|
#include "mozpkix/Input.h"
|
||||||
#include "mozpkix/Result.h"
|
#include "mozpkix/Result.h"
|
||||||
|
|
||||||
@@ -65,12 +66,17 @@ struct SignedCertificateTimestamp {
|
|||||||
V1 = 0,
|
V1 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pkix::Result DecodeExtensions();
|
||||||
|
|
||||||
Version version;
|
Version version;
|
||||||
Buffer logId;
|
Buffer logId;
|
||||||
// "timestamp" is the current time in milliseconds, measured since the epoch,
|
// "timestamp" is the current time in milliseconds, measured since the epoch,
|
||||||
// ignoring leap seconds. See RFC 6962, Section 3.2.
|
// ignoring leap seconds. See RFC 6962, Section 3.2.
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
Buffer extensions;
|
Buffer extensions;
|
||||||
|
// Maybe the index of the entry in the log, if specified by a LeafIndex
|
||||||
|
// extension in `extensions`.
|
||||||
|
Maybe<uint64_t> leafIndex;
|
||||||
DigitallySigned signature;
|
DigitallySigned signature;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ class CTLogVerifierTest : public ::testing::Test {
|
|||||||
void TearDown() override { signature_cache_free(mSignatureCache); }
|
void TearDown() override { signature_cache_free(mSignatureCache); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CTLogVerifier mLog = CTLogVerifier(-1, CTLogState::Admissible, 0);
|
CTLogVerifier mLog =
|
||||||
|
CTLogVerifier(-1, CTLogState::Admissible, CTLogFormat::RFC6962, 0);
|
||||||
// For some reason, the templating makes it impossible to use UniquePtr here.
|
// For some reason, the templating makes it impossible to use UniquePtr here.
|
||||||
SignatureCache* mSignatureCache;
|
SignatureCache* mSignatureCache;
|
||||||
};
|
};
|
||||||
@@ -115,7 +116,7 @@ TEST_F(CTLogVerifierTest, ExcessDataInPublicKey) {
|
|||||||
std::string extra = "extra";
|
std::string extra = "extra";
|
||||||
key.insert(key.end(), extra.begin(), extra.end());
|
key.insert(key.end(), extra.begin(), extra.end());
|
||||||
|
|
||||||
CTLogVerifier log(-1, CTLogState::Admissible, 0);
|
CTLogVerifier log(-1, CTLogState::Admissible, CTLogFormat::RFC6962, 0);
|
||||||
EXPECT_NE(Success, log.Init(InputForBuffer(key)));
|
EXPECT_NE(Success, log.Init(InputForBuffer(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class CTObjectsExtractorTest : public ::testing::Test {
|
|||||||
Buffer mEmbeddedCert;
|
Buffer mEmbeddedCert;
|
||||||
Buffer mCaCert;
|
Buffer mCaCert;
|
||||||
Buffer mCaCertSPKI;
|
Buffer mCaCertSPKI;
|
||||||
CTLogVerifier mLog = CTLogVerifier(-1, CTLogState::Admissible, 0);
|
CTLogVerifier mLog =
|
||||||
|
CTLogVerifier(-1, CTLogState::Admissible, CTLogFormat::RFC6962, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(CTObjectsExtractorTest, ExtractPrecert) {
|
TEST_F(CTObjectsExtractorTest, ExtractPrecert) {
|
||||||
|
|||||||
@@ -35,25 +35,30 @@ class CTPolicyEnforcerTest : public ::testing::Test {
|
|||||||
|
|
||||||
void AddSct(VerifiedSCTList& verifiedScts, size_t logNo,
|
void AddSct(VerifiedSCTList& verifiedScts, size_t logNo,
|
||||||
CTLogOperatorId operatorId, SCTOrigin origin, uint64_t timestamp,
|
CTLogOperatorId operatorId, SCTOrigin origin, uint64_t timestamp,
|
||||||
CTLogState logState = CTLogState::Admissible) {
|
CTLogState logState = CTLogState::Admissible,
|
||||||
|
CTLogFormat logFormat = CTLogFormat::RFC6962,
|
||||||
|
Maybe<uint64_t> leafIndex = Nothing()) {
|
||||||
SignedCertificateTimestamp sct;
|
SignedCertificateTimestamp sct;
|
||||||
sct.version = SignedCertificateTimestamp::Version::V1;
|
sct.version = SignedCertificateTimestamp::Version::V1;
|
||||||
sct.timestamp = timestamp;
|
sct.timestamp = timestamp;
|
||||||
|
sct.leafIndex = leafIndex;
|
||||||
Buffer logId;
|
Buffer logId;
|
||||||
GetLogId(logId, logNo);
|
GetLogId(logId, logNo);
|
||||||
sct.logId = std::move(logId);
|
sct.logId = std::move(logId);
|
||||||
VerifiedSCT verifiedSct(std::move(sct), origin, operatorId, logState,
|
VerifiedSCT verifiedSct(std::move(sct), origin, operatorId, logState,
|
||||||
LOG_TIMESTAMP);
|
logFormat, LOG_TIMESTAMP);
|
||||||
verifiedScts.push_back(std::move(verifiedSct));
|
verifiedScts.push_back(std::move(verifiedSct));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddMultipleScts(VerifiedSCTList& verifiedScts, size_t logsCount,
|
void AddMultipleScts(VerifiedSCTList& verifiedScts, size_t logsCount,
|
||||||
uint8_t operatorsCount, SCTOrigin origin,
|
uint8_t operatorsCount, SCTOrigin origin,
|
||||||
uint64_t timestamp,
|
uint64_t timestamp,
|
||||||
CTLogState logState = CTLogState::Admissible) {
|
CTLogState logState = CTLogState::Admissible,
|
||||||
|
CTLogFormat logFormat = CTLogFormat::RFC6962) {
|
||||||
for (size_t logNo = 0; logNo < logsCount; logNo++) {
|
for (size_t logNo = 0; logNo < logsCount; logNo++) {
|
||||||
CTLogOperatorId operatorId = logNo % operatorsCount;
|
CTLogOperatorId operatorId = logNo % operatorsCount;
|
||||||
AddSct(verifiedScts, logNo, operatorId, origin, timestamp, logState);
|
AddSct(verifiedScts, logNo, operatorId, origin, timestamp, logState,
|
||||||
|
logFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,5 +297,84 @@ TEST_F(CTPolicyEnforcerTest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithAtLeastOneRFC6962Log) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::RFC6962);
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest,
|
||||||
|
ConformsToCTPolicyWithAtLeastOneRFC6962LogEmbedded) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
// 3 embedded SCTs required for DEFAULT_LIFETIME.
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::RFC6962);
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyWithNoRFC6962Logs) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest,
|
||||||
|
DoesNotConformToCTPolicyWithNoRFC6962LogsEmbedded) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
// 3 embedded SCTs required for DEFAULT_LIFETIME.
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest,
|
||||||
|
DoesNotConformToCTPolicyWithSCTFromTiledLogWithNoLeafIndex) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Nothing());
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::RFC6962);
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTPolicyEnforcerTest,
|
||||||
|
DoesNotConformToCTPolicyWithSCTFromTiledLogWithNoLeafIndexEmbedded) {
|
||||||
|
VerifiedSCTList scts;
|
||||||
|
|
||||||
|
// 3 embedded SCTs required for DEFAULT_LIFETIME.
|
||||||
|
AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Some(23));
|
||||||
|
AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::Tiled, Nothing());
|
||||||
|
AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1,
|
||||||
|
CTLogState::Admissible, CTLogFormat::RFC6962);
|
||||||
|
|
||||||
|
CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ct
|
} // namespace ct
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -192,6 +192,90 @@ TEST_F(CTSerializationTest, DecodesSignedCertificateTimestamp) {
|
|||||||
const size_t expectedSignatureLength = 71;
|
const size_t expectedSignatureLength = 71;
|
||||||
EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.size());
|
EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.size());
|
||||||
EXPECT_TRUE(sct.extensions.empty());
|
EXPECT_TRUE(sct.extensions.empty());
|
||||||
|
EXPECT_TRUE(sct.leafIndex.isNothing());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTSerializationTest,
|
||||||
|
DecodesSignedCertificateTimestampWithLeafIndexExtension) {
|
||||||
|
Buffer encodedSctBuffer =
|
||||||
|
GetTestSignedCertificateTimestampWithLeafIndexExtension();
|
||||||
|
Input encodedSctInput = InputForBuffer(encodedSctBuffer);
|
||||||
|
Reader encodedSctReader(encodedSctInput);
|
||||||
|
|
||||||
|
SignedCertificateTimestamp sct;
|
||||||
|
ASSERT_EQ(Success, DecodeSignedCertificateTimestamp(encodedSctReader, sct));
|
||||||
|
EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version);
|
||||||
|
EXPECT_EQ(GetTestPublicKeyId(), sct.logId);
|
||||||
|
const uint64_t expectedTime = 1365181456089;
|
||||||
|
EXPECT_EQ(expectedTime, sct.timestamp);
|
||||||
|
const size_t expectedSignatureLength = 71;
|
||||||
|
EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.size());
|
||||||
|
EXPECT_FALSE(sct.extensions.empty());
|
||||||
|
ASSERT_TRUE(sct.leafIndex.isSome());
|
||||||
|
EXPECT_EQ(sct.leafIndex.value(), 52U);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTSerializationTest,
|
||||||
|
FailsDecodingSignedCertificateTimestampWithTwoLeafIndexExtensions) {
|
||||||
|
Buffer encodedSctBuffer =
|
||||||
|
GetTestSignedCertificateTimestampWithTwoLeafIndexExtensions();
|
||||||
|
Input encodedSctInput = InputForBuffer(encodedSctBuffer);
|
||||||
|
Reader encodedSctReader(encodedSctInput);
|
||||||
|
|
||||||
|
SignedCertificateTimestamp sct;
|
||||||
|
ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
|
||||||
|
DecodeSignedCertificateTimestamp(encodedSctReader, sct));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTSerializationTest,
|
||||||
|
DecodesSignedCertificateTimestampWithUnknownExtension) {
|
||||||
|
Buffer encodedSctBuffer =
|
||||||
|
GetTestSignedCertificateTimestampWithUnknownExtension();
|
||||||
|
Input encodedSctInput = InputForBuffer(encodedSctBuffer);
|
||||||
|
Reader encodedSctReader(encodedSctInput);
|
||||||
|
|
||||||
|
SignedCertificateTimestamp sct;
|
||||||
|
ASSERT_EQ(Success, DecodeSignedCertificateTimestamp(encodedSctReader, sct));
|
||||||
|
EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version);
|
||||||
|
EXPECT_EQ(GetTestPublicKeyId(), sct.logId);
|
||||||
|
const uint64_t expectedTime = 1365181456089;
|
||||||
|
EXPECT_EQ(expectedTime, sct.timestamp);
|
||||||
|
const size_t expectedSignatureLength = 71;
|
||||||
|
EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.size());
|
||||||
|
EXPECT_FALSE(sct.extensions.empty());
|
||||||
|
EXPECT_TRUE(sct.leafIndex.isNothing());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTSerializationTest,
|
||||||
|
DecodesSignedCertificateTimestampWithUnknownAndLeafIndexExtensions) {
|
||||||
|
Buffer encodedSctBuffer =
|
||||||
|
GetTestSignedCertificateTimestampWithUnknownAndLeafIndexExtensions();
|
||||||
|
Input encodedSctInput = InputForBuffer(encodedSctBuffer);
|
||||||
|
Reader encodedSctReader(encodedSctInput);
|
||||||
|
|
||||||
|
SignedCertificateTimestamp sct;
|
||||||
|
ASSERT_EQ(Success, DecodeSignedCertificateTimestamp(encodedSctReader, sct));
|
||||||
|
EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version);
|
||||||
|
EXPECT_EQ(GetTestPublicKeyId(), sct.logId);
|
||||||
|
const uint64_t expectedTime = 1365181456089;
|
||||||
|
EXPECT_EQ(expectedTime, sct.timestamp);
|
||||||
|
const size_t expectedSignatureLength = 71;
|
||||||
|
EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.size());
|
||||||
|
EXPECT_FALSE(sct.extensions.empty());
|
||||||
|
ASSERT_TRUE(sct.leafIndex.isSome());
|
||||||
|
EXPECT_EQ(sct.leafIndex.value(), 81U);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CTSerializationTest,
|
||||||
|
FailsDecodingSignedCertificateTimestampWithTooShortExtension) {
|
||||||
|
Buffer encodedSctBuffer =
|
||||||
|
GetTestSignedCertificateTimestampWithTooShortExtension();
|
||||||
|
Input encodedSctInput = InputForBuffer(encodedSctBuffer);
|
||||||
|
Reader encodedSctReader(encodedSctInput);
|
||||||
|
|
||||||
|
SignedCertificateTimestamp sct;
|
||||||
|
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||||
|
DecodeSignedCertificateTimestamp(encodedSctReader, sct));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CTSerializationTest, FailsDecodingInvalidSignedCertificateTimestamp) {
|
TEST_F(CTSerializationTest, FailsDecodingInvalidSignedCertificateTimestamp) {
|
||||||
|
|||||||
@@ -87,6 +87,55 @@ const char kTestSignedCertificateTimestamp[] =
|
|||||||
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
"89a2c0187ef5a5";
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
|
// The signatures on the following "SCT"s are not actually valid. The intent is
|
||||||
|
// to test the parsing of extensions.
|
||||||
|
const char kTestSignedCertificateTimestampWithLeafIndexExtension[] =
|
||||||
|
"00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7640000013d"
|
||||||
|
"db27ded9"
|
||||||
|
"0008" // 8 bytes of extensions
|
||||||
|
"0000050000000034" // leaf_index of 52
|
||||||
|
"0403004730450220606e10ae5c2d5a1b0aed49dc4937f48de71a4e9784e9c2"
|
||||||
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
|
const char kTestSignedCertificateTimestampWithTwoLeafIndexExtensions[] =
|
||||||
|
"00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7640000013d"
|
||||||
|
"db27ded9"
|
||||||
|
"0010" // 16 bytes of extensions
|
||||||
|
"0000050000000034" // leaf_index of 52
|
||||||
|
"0000050000000051" // leaf_index of 81
|
||||||
|
"0403004730450220606e10ae5c2d5a1b0aed49dc4937f48de71a4e9784e9c2"
|
||||||
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
|
const char kTestSignedCertificateTimestampWithUnknownExtension[] =
|
||||||
|
"00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7640000013d"
|
||||||
|
"db27ded9"
|
||||||
|
"0008" // 8 bytes of extensions
|
||||||
|
"0100050000000034" // an (unknown) extension with id 1
|
||||||
|
"0403004730450220606e10ae5c2d5a1b0aed49dc4937f48de71a4e9784e9c2"
|
||||||
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
|
const char kTestSignedCertificateTimestampWithUnknownAndLeafIndexExtensions[] =
|
||||||
|
"00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7640000013d"
|
||||||
|
"db27ded9"
|
||||||
|
"0010" // 16 bytes of extensions
|
||||||
|
"0100050000000034" // an (unknown) extension with id 1
|
||||||
|
"0000050000000051" // leaf_index of 81
|
||||||
|
"0403004730450220606e10ae5c2d5a1b0aed49dc4937f48de71a4e9784e9c2"
|
||||||
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
|
const char kTestSignedCertificateTimestampWithTooShortExtension[] =
|
||||||
|
"00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7640000013d"
|
||||||
|
"db27ded9"
|
||||||
|
"0008" // 8 bytes of extensions
|
||||||
|
"000005000034" // 3 bytes of extension data when there should be 5
|
||||||
|
"0403004730450220606e10ae5c2d5a1b0aed49dc4937f48de71a4e9784e9c2"
|
||||||
|
"08dfbfe9ef536cf7f2022100beb29c72d7d06d61d06bdb38a069469aa86fe12e18bb7cc456"
|
||||||
|
"89a2c0187ef5a5";
|
||||||
|
|
||||||
// ct-server-key-public.pem
|
// ct-server-key-public.pem
|
||||||
const char kEcP256PublicKey[] =
|
const char kEcP256PublicKey[] =
|
||||||
"3059301306072a8648ce3d020106082a8648ce3d0301070342000499783cb14533c0161a5a"
|
"3059301306072a8648ce3d020106082a8648ce3d0301070342000499783cb14533c0161a5a"
|
||||||
@@ -527,6 +576,27 @@ Buffer GetTestSignedCertificateTimestamp() {
|
|||||||
return HexToBytes(kTestSignedCertificateTimestamp);
|
return HexToBytes(kTestSignedCertificateTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithLeafIndexExtension() {
|
||||||
|
return HexToBytes(kTestSignedCertificateTimestampWithLeafIndexExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithTwoLeafIndexExtensions() {
|
||||||
|
return HexToBytes(kTestSignedCertificateTimestampWithTwoLeafIndexExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithUnknownExtension() {
|
||||||
|
return HexToBytes(kTestSignedCertificateTimestampWithUnknownExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithUnknownAndLeafIndexExtensions() {
|
||||||
|
return HexToBytes(
|
||||||
|
kTestSignedCertificateTimestampWithUnknownAndLeafIndexExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithTooShortExtension() {
|
||||||
|
return HexToBytes(kTestSignedCertificateTimestampWithTooShortExtension);
|
||||||
|
}
|
||||||
|
|
||||||
Buffer GetTestInclusionProof() { return HexToBytes(kTestInclusionProof); }
|
Buffer GetTestInclusionProof() { return HexToBytes(kTestInclusionProof); }
|
||||||
|
|
||||||
Buffer GetTestInclusionProofUnexpectedData() {
|
Buffer GetTestInclusionProofUnexpectedData() {
|
||||||
|
|||||||
@@ -39,8 +39,13 @@ Buffer GetTestDigitallySigned();
|
|||||||
// Returns the source data of the test DigitallySigned.
|
// Returns the source data of the test DigitallySigned.
|
||||||
Buffer GetTestDigitallySignedData();
|
Buffer GetTestDigitallySignedData();
|
||||||
|
|
||||||
// Returns the binary representation of a test serialized SCT.
|
// Returns the binary representation of various test SCTs.
|
||||||
Buffer GetTestSignedCertificateTimestamp();
|
Buffer GetTestSignedCertificateTimestamp();
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithLeafIndexExtension();
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithTwoLeafIndexExtensions();
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithUnknownExtension();
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithUnknownAndLeafIndexExtensions();
|
||||||
|
Buffer GetTestSignedCertificateTimestampWithTooShortExtension();
|
||||||
|
|
||||||
// Returns the binary representation of a test serialized InclusionProof.
|
// Returns the binary representation of a test serialized InclusionProof.
|
||||||
Buffer GetTestInclusionProof();
|
Buffer GetTestInclusionProof();
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class MultiLogCTVerifierTest : public ::testing::Test {
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
CTLogVerifier log(mLogOperatorID, CTLogState::Admissible, 0);
|
CTLogVerifier log(mLogOperatorID, CTLogState::Admissible,
|
||||||
|
CTLogFormat::RFC6962, 0);
|
||||||
;
|
;
|
||||||
ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
|
ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
|
||||||
mVerifier.AddLog(std::move(log));
|
mVerifier.AddLog(std::move(log));
|
||||||
@@ -222,7 +223,8 @@ TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) {
|
|||||||
TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromDisqualifiedLog) {
|
TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromDisqualifiedLog) {
|
||||||
MultiLogCTVerifier verifier;
|
MultiLogCTVerifier verifier;
|
||||||
const uint64_t retiredTime = 12345u;
|
const uint64_t retiredTime = 12345u;
|
||||||
CTLogVerifier log(mLogOperatorID, CTLogState::Retired, retiredTime);
|
CTLogVerifier log(mLogOperatorID, CTLogState::Retired, CTLogFormat::RFC6962,
|
||||||
|
retiredTime);
|
||||||
ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
|
ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
|
||||||
verifier.AddLog(std::move(log));
|
verifier.AddLog(std::move(log));
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ function add_tests_in_mode(mode) {
|
|||||||
Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT,
|
Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
// This certificate has an embedded SCT from a tiled log.
|
||||||
|
add_ct_test(
|
||||||
|
"ct-tiled-valid.example.com",
|
||||||
|
Ci.nsITransportSecurityInfo.CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT,
|
||||||
|
true
|
||||||
|
);
|
||||||
// This certificate has only 2 embedded SCTs, and so is not policy-compliant.
|
// This certificate has only 2 embedded SCTs, and so is not policy-compliant.
|
||||||
add_ct_test(
|
add_ct_test(
|
||||||
"ct-insufficient-scts.example.com",
|
"ct-insufficient-scts.example.com",
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
jSTJxocud+zZajmigOfMIvcYUKVD3ieiLg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
issuer:Test CA
|
||||||
|
subject:ct-tiled-valid.example.com
|
||||||
|
extension:subjectAlternativeName:*.example.com
|
||||||
|
extension:embeddedSCTList:default:20160101,secp256r1:20160101,ev:20160101:567502607955
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIF3DCCBMSgAwIBAgIUS2SODmE9dXhGEYS8JfCogtARiyEwDQYJKoZIhvcNAQEL
|
MIIFRTCCBC2gAwIBAgIUG4/k+n+iibx5ZgMTEJsAirIw46YwDQYJKoZIhvcNAQEL
|
||||||
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAiGA8yMDIzMTEyODAwMDAwMFoYDzIwMjYw
|
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAiGA8yMDIzMTEyODAwMDAwMFoYDzIwMjYw
|
||||||
MjA1MDAwMDAwWjAlMSMwIQYDVQQDDBpjdC11bmtub3duLWxvZy5leGFtcGxlLmNv
|
MjA1MDAwMDAwWjAlMSMwIQYDVQQDDBpjdC11bmtub3duLWxvZy5leGFtcGxlLmNv
|
||||||
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogG
|
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogG
|
||||||
@@ -8,27 +8,24 @@ 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
|
WDb3zi3AJNht
|
||||||
XAJpdu5HwOj2+4aCNw6drMg+b/Dig+EpOTSBhalofyJxi3Lv/Kedzc9wlxqvmUvm
|
|
||||||
iMxWJob8wwaFRoL4YNBxxZEYI+Hebw8kePHhtwZ7h9q/BsgFajsWn5ay3PXmVvD2
|
|
||||||
Em16teHaNfB2r3e6sjuZBw==
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
issuer:Test CA
|
issuer:Test CA
|
||||||
subject:ct-unknown-log.example.com
|
subject:ct-unknown-log.example.com
|
||||||
extension:subjectAlternativeName:*.example.com
|
extension:subjectAlternativeName:*.example.com
|
||||||
extension:embeddedSCTList:default:20160101,secp256r1:20160101,ev:20160101
|
extension:embeddedSCTList:default:20160101,secp256r1:20160101,secp384r1:20160101
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "59.18",
|
"version": "59.19",
|
||||||
"log_list_timestamp": "2025-07-27T12:54:32Z",
|
"log_list_timestamp": "2025-07-28T12:53:51Z",
|
||||||
"operators": [
|
"operators": [
|
||||||
{
|
{
|
||||||
"name": "Google",
|
"name": "Google",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ certificatePolicies:[<policy OID>,...]
|
|||||||
nameConstraints:{permitted,excluded}:[<dNSName|directoryName>,...]
|
nameConstraints:{permitted,excluded}:[<dNSName|directoryName>,...]
|
||||||
nsCertType:sslServer
|
nsCertType:sslServer
|
||||||
TLSFeature:[<TLSFeature>,...]
|
TLSFeature:[<TLSFeature>,...]
|
||||||
embeddedSCTList:[<key specification>:<YYYYMMDD>,...]
|
embeddedSCTList:[<key specification>:<YYYYMMDD>[:<leaf index>],...]
|
||||||
delegationUsage:
|
delegationUsage:
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
@@ -109,12 +109,12 @@ class UnknownBaseError(Error):
|
|||||||
"""Base class for handling unexpected input in this module."""
|
"""Base class for handling unexpected input in this module."""
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
super(UnknownBaseError, self).__init__()
|
super().__init__()
|
||||||
self.value = value
|
self.value = value
|
||||||
self.category = "input"
|
self.category = "input"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Unknown %s type "%s"' % (self.category, repr(self.value))
|
return f'Unknown {self.category} type "{repr(self.value)}"'
|
||||||
|
|
||||||
|
|
||||||
class UnknownAlgorithmTypeError(UnknownBaseError):
|
class UnknownAlgorithmTypeError(UnknownBaseError):
|
||||||
@@ -210,18 +210,18 @@ class InvalidSCTSpecification(Error):
|
|||||||
"""Helper exception type to handle invalid SCT specifications."""
|
"""Helper exception type to handle invalid SCT specifications."""
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
super(InvalidSCTSpecification, self).__init__()
|
super().__init__()
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return repr('invalid SCT specification "{}"' % self.value)
|
return f'invalid SCT specification "{self.value}"'
|
||||||
|
|
||||||
|
|
||||||
class InvalidSerialNumber(Error):
|
class InvalidSerialNumber(Error):
|
||||||
"""Exception type to handle invalid serial numbers."""
|
"""Exception type to handle invalid serial numbers."""
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
super(InvalidSerialNumber, self).__init__()
|
super().__init__()
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -254,7 +254,7 @@ def stringToDN(string, tag=None):
|
|||||||
optional implicit tag in cases where the Name needs to be tagged
|
optional implicit tag in cases where the Name needs to be tagged
|
||||||
differently."""
|
differently."""
|
||||||
if string and "/" not in string:
|
if string and "/" not in string:
|
||||||
string = "/CN=%s" % string
|
string = f"/CN={string}"
|
||||||
rdns = rfc2459.RDNSequence()
|
rdns = rfc2459.RDNSequence()
|
||||||
pattern = "/(C|ST|L|O|OU|CN|emailAddress)="
|
pattern = "/(C|ST|L|O|OU|CN|emailAddress)="
|
||||||
split = re.split(pattern, string)
|
split = re.split(pattern, string)
|
||||||
@@ -621,10 +621,11 @@ class Certificate:
|
|||||||
def addCertificatePolicies(self, policyOIDs, critical):
|
def addCertificatePolicies(self, policyOIDs, critical):
|
||||||
policies = rfc2459.CertificatePolicies()
|
policies = rfc2459.CertificatePolicies()
|
||||||
for pos, policyOID in enumerate(policyOIDs.split(",")):
|
for pos, policyOID in enumerate(policyOIDs.split(",")):
|
||||||
if policyOID == "any":
|
policyOIDMapped = policyOID
|
||||||
policyOID = "2.5.29.32.0"
|
if policyOIDMapped == "any":
|
||||||
|
policyOIDMapped = "2.5.29.32.0"
|
||||||
policy = rfc2459.PolicyInformation()
|
policy = rfc2459.PolicyInformation()
|
||||||
policyIdentifier = rfc2459.CertPolicyId(policyOID)
|
policyIdentifier = rfc2459.CertPolicyId(policyOIDMapped)
|
||||||
policy["policyIdentifier"] = policyIdentifier
|
policy["policyIdentifier"] = policyIdentifier
|
||||||
policies.setComponentByPosition(pos, policy)
|
policies.setComponentByPosition(pos, policy)
|
||||||
self.addExtension(rfc2459.id_ce_certificatePolicies, policies, critical)
|
self.addExtension(rfc2459.id_ce_certificatePolicies, policies, critical)
|
||||||
@@ -696,15 +697,20 @@ class Certificate:
|
|||||||
(scts, critical) = self.savedEmbeddedSCTListData
|
(scts, critical) = self.savedEmbeddedSCTListData
|
||||||
encodedSCTs = []
|
encodedSCTs = []
|
||||||
for sctSpec in scts.split(","):
|
for sctSpec in scts.split(","):
|
||||||
match = re.search(r"(\w+):(\d{8})", sctSpec)
|
match = re.search(r"(\w+):(\d{8}):?(\d+)?", sctSpec)
|
||||||
if not match:
|
if not match:
|
||||||
raise InvalidSCTSpecification(sctSpec)
|
raise InvalidSCTSpecification(sctSpec)
|
||||||
keySpec = match.group(1)
|
keySpec = match.group(1)
|
||||||
|
leafIndex = match.group(3)
|
||||||
|
if leafIndex:
|
||||||
|
leafIndex = int(leafIndex)
|
||||||
key = pykey.keyFromSpecification(keySpec)
|
key = pykey.keyFromSpecification(keySpec)
|
||||||
time = datetime.datetime.strptime(match.group(2), "%Y%m%d")
|
time = datetime.datetime.strptime(match.group(2), "%Y%m%d")
|
||||||
tbsCertificate = self.getTBSCertificate()
|
tbsCertificate = self.getTBSCertificate()
|
||||||
tbsDER = encoder.encode(tbsCertificate)
|
tbsDER = encoder.encode(tbsCertificate)
|
||||||
sct = pyct.SCT(key, time, pyct.PrecertEntry(tbsDER, self.issuerKey))
|
sct = pyct.SCT(
|
||||||
|
key, time, pyct.PrecertEntry(tbsDER, self.issuerKey), leafIndex
|
||||||
|
)
|
||||||
signed = sct.signAndEncode()
|
signed = sct.signAndEncode()
|
||||||
lengthPrefix = pack("!H", len(signed))
|
lengthPrefix = pack("!H", len(signed))
|
||||||
encodedSCTs.append(lengthPrefix + signed)
|
encodedSCTs.append(lengthPrefix + signed)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ to the output object. The specification is as follows:
|
|||||||
timestamp:<YYYYMMDD>
|
timestamp:<YYYYMMDD>
|
||||||
[key:<key specification>]
|
[key:<key specification>]
|
||||||
[tamper]
|
[tamper]
|
||||||
|
[leafIndex:<leaf index>]
|
||||||
certificate:
|
certificate:
|
||||||
<certificate specification>
|
<certificate specification>
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ class InvalidKeyError(Exception):
|
|||||||
self.key = key
|
self.key = key
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Invalid key: "%s"' % str(self.key)
|
return f'Invalid key: "{str(self.key)}"'
|
||||||
|
|
||||||
|
|
||||||
class UnknownSignedEntryType(Exception):
|
class UnknownSignedEntryType(Exception):
|
||||||
@@ -58,7 +59,7 @@ class UnknownSignedEntryType(Exception):
|
|||||||
self.signedEntry = signedEntry
|
self.signedEntry = signedEntry
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Unknown SignedEntry type: "%s"' % str(self.signedEntry)
|
return f'Unknown SignedEntry type: "{str(self.signedEntry)}"'
|
||||||
|
|
||||||
|
|
||||||
class SignedEntry:
|
class SignedEntry:
|
||||||
@@ -84,11 +85,12 @@ class X509Entry(SignedEntry):
|
|||||||
class SCT:
|
class SCT:
|
||||||
"""SCT represents a Signed Certificate Timestamp."""
|
"""SCT represents a Signed Certificate Timestamp."""
|
||||||
|
|
||||||
def __init__(self, key, date, signedEntry):
|
def __init__(self, key, date, signedEntry, leafIndex=None):
|
||||||
self.key = key
|
self.key = key
|
||||||
self.timestamp = calendar.timegm(date.timetuple()) * 1000
|
self.timestamp = calendar.timegm(date.timetuple()) * 1000
|
||||||
self.signedEntry = signedEntry
|
self.signedEntry = signedEntry
|
||||||
self.tamper = False
|
self.tamper = False
|
||||||
|
self.leafIndex = leafIndex
|
||||||
|
|
||||||
def signAndEncode(self):
|
def signAndEncode(self):
|
||||||
"""Returns a signed and encoded representation of the
|
"""Returns a signed and encoded representation of the
|
||||||
@@ -100,8 +102,7 @@ class SCT:
|
|||||||
# entry_type (two bytes (one 0 byte followed by one 0 byte for
|
# entry_type (two bytes (one 0 byte followed by one 0 byte for
|
||||||
# X509Entry or one 1 byte for PrecertEntry)
|
# X509Entry or one 1 byte for PrecertEntry)
|
||||||
# signed_entry (bytes of X509Entry or PrecertEntry)
|
# signed_entry (bytes of X509Entry or PrecertEntry)
|
||||||
# extensions (2-byte-length-prefixed, currently empty (so two 0
|
# extensions (2-byte-length-prefixed)
|
||||||
# bytes))
|
|
||||||
# A X509Entry is:
|
# A X509Entry is:
|
||||||
# certificate (3-byte-length-prefixed data)
|
# certificate (3-byte-length-prefixed data)
|
||||||
# A PrecertEntry is:
|
# A PrecertEntry is:
|
||||||
@@ -125,7 +126,18 @@ class SCT:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise UnknownSignedEntryType(self.signedEntry)
|
raise UnknownSignedEntryType(self.signedEntry)
|
||||||
data = b"\0\0" + timestamp + b"\0" + entry_with_type + b"\0\0"
|
extensions = []
|
||||||
|
if self.leafIndex:
|
||||||
|
# An extension consists of 1 byte to identify the extension type, 2
|
||||||
|
# big-endian bytes for the length of the extension data, and then
|
||||||
|
# the extension data.
|
||||||
|
# The type of leaf_index is 0, and its data consists of 5 bytes.
|
||||||
|
extensions = [b"\0\0\5" + self.leafIndex.to_bytes(5, byteorder="big")]
|
||||||
|
extensionsLength = sum(map(len, extensions))
|
||||||
|
extensionsEncoded = extensionsLength.to_bytes(2, byteorder="big") + b"".join(
|
||||||
|
extensions
|
||||||
|
)
|
||||||
|
data = b"\0\0" + timestamp + b"\0" + entry_with_type + extensionsEncoded
|
||||||
if isinstance(self.key, pykey.ECCKey):
|
if isinstance(self.key, pykey.ECCKey):
|
||||||
signatureByte = b"\3"
|
signatureByte = b"\3"
|
||||||
elif isinstance(self.key, pykey.RSAKey):
|
elif isinstance(self.key, pykey.RSAKey):
|
||||||
@@ -143,8 +155,7 @@ class SCT:
|
|||||||
# id (32 bytes of SHA-256 hash of the signing key, as
|
# id (32 bytes of SHA-256 hash of the signing key, as
|
||||||
# DER-encoded SPKI)
|
# DER-encoded SPKI)
|
||||||
# timestamp (8 bytes, milliseconds since the epoch)
|
# timestamp (8 bytes, milliseconds since the epoch)
|
||||||
# extensions (2-byte-length-prefixed data, currently
|
# extensions (2-byte-length-prefixed data)
|
||||||
# empty)
|
|
||||||
# hash (one 4 byte representing sha256)
|
# hash (one 4 byte representing sha256)
|
||||||
# signature (one byte - 1 for RSA and 3 for ECDSA)
|
# signature (one byte - 1 for RSA and 3 for ECDSA)
|
||||||
# signature (2-byte-length-prefixed data)
|
# signature (2-byte-length-prefixed data)
|
||||||
@@ -156,7 +167,8 @@ class SCT:
|
|||||||
b"\0"
|
b"\0"
|
||||||
+ key_id
|
+ key_id
|
||||||
+ timestamp
|
+ timestamp
|
||||||
+ b"\0\0\4"
|
+ extensionsEncoded
|
||||||
|
+ b"\4"
|
||||||
+ signatureByte
|
+ signatureByte
|
||||||
+ signature_len_prefix
|
+ signature_len_prefix
|
||||||
+ signature
|
+ signature
|
||||||
@@ -168,26 +180,30 @@ class SCT:
|
|||||||
certificateSpecification = StringIO()
|
certificateSpecification = StringIO()
|
||||||
readingCertificateSpecification = False
|
readingCertificateSpecification = False
|
||||||
tamper = False
|
tamper = False
|
||||||
|
leafIndex = None
|
||||||
for line in specStream.readlines():
|
for line in specStream.readlines():
|
||||||
line = line.strip()
|
lineStripped = line.strip()
|
||||||
if readingCertificateSpecification:
|
if readingCertificateSpecification:
|
||||||
print(line, file=certificateSpecification)
|
print(lineStripped, file=certificateSpecification)
|
||||||
elif line == "certificate:":
|
elif lineStripped == "certificate:":
|
||||||
readingCertificateSpecification = True
|
readingCertificateSpecification = True
|
||||||
elif line.startswith("key:"):
|
elif lineStripped.startswith("key:"):
|
||||||
key = pykey.keyFromSpecification(line[len("key:") :])
|
key = pykey.keyFromSpecification(lineStripped[len("key:") :])
|
||||||
elif line.startswith("timestamp:"):
|
elif lineStripped.startswith("timestamp:"):
|
||||||
timestamp = datetime.datetime.strptime(
|
timestamp = datetime.datetime.strptime(
|
||||||
line[len("timestamp:") :], "%Y%m%d"
|
lineStripped[len("timestamp:") :], "%Y%m%d"
|
||||||
)
|
)
|
||||||
elif line == "tamper":
|
elif lineStripped == "tamper":
|
||||||
tamper = True
|
tamper = True
|
||||||
|
elif lineStripped.startswith("leafIndex:"):
|
||||||
|
leafIndex = int(lineStripped[len("leafIndex:") :])
|
||||||
else:
|
else:
|
||||||
raise pycert.UnknownParameterTypeError(line)
|
raise pycert.UnknownParameterTypeError(lineStripped)
|
||||||
certificateSpecification.seek(0)
|
certificateSpecification.seek(0)
|
||||||
certificate = pycert.Certificate(certificateSpecification).toDER()
|
certificate = pycert.Certificate(certificateSpecification).toDER()
|
||||||
sct = SCT(key, timestamp, X509Entry(certificate))
|
sct = SCT(key, timestamp, X509Entry(certificate))
|
||||||
sct.tamper = tamper
|
sct.tamper = tamper
|
||||||
|
sct.leafIndex = leafIndex
|
||||||
return sct
|
return sct
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,10 +58,16 @@ enum class CTLogState {
|
|||||||
Retired,
|
Retired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CTLogFormat {
|
||||||
|
RFC6962,
|
||||||
|
Tiled,
|
||||||
|
};
|
||||||
|
|
||||||
struct CTLogInfo {
|
struct CTLogInfo {
|
||||||
// See bug 1338873 about making these fields const.
|
// See bug 1338873 about making these fields const.
|
||||||
const char* name;
|
const char* name;
|
||||||
CTLogState state;
|
CTLogState state;
|
||||||
|
CTLogFormat format;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
// Index within kCTLogOperatorList.
|
// Index within kCTLogOperatorList.
|
||||||
size_t operatorIndex;
|
size_t operatorIndex;
|
||||||
@@ -122,7 +128,7 @@ def get_operator_index(json_data, target_name):
|
|||||||
|
|
||||||
|
|
||||||
LOG_INFO_TEMPLATE = """\
|
LOG_INFO_TEMPLATE = """\
|
||||||
{$description, $state,
|
{$description, $state, $log_format,
|
||||||
$timestamp, // $timestamp_comment
|
$timestamp, // $timestamp_comment
|
||||||
$operator_index,$spaces // $operator_comment
|
$operator_index,$spaces // $operator_comment
|
||||||
$indented_log_key,
|
$indented_log_key,
|
||||||
@@ -140,31 +146,26 @@ def map_state(state):
|
|||||||
states to be included are 'qualified', 'usable', 'readonly', or 'retired'.
|
states to be included are 'qualified', 'usable', 'readonly', or 'retired'.
|
||||||
Valid states that are not to be included are 'pending' or 'rejected'.
|
Valid states that are not to be included are 'pending' or 'rejected'.
|
||||||
"""
|
"""
|
||||||
if state == "qualified" or state == "usable" or state == "readonly":
|
if state in {"qualified", "usable", "readonly"}:
|
||||||
return "CTLogState::Admissible"
|
return "CTLogState::Admissible"
|
||||||
elif state == "retired":
|
elif state == "retired":
|
||||||
return "CTLogState::Retired"
|
return "CTLogState::Retired"
|
||||||
elif state == "pending" or state == "rejected":
|
elif state in {"pending", "rejected"}:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
raise UnhandledLogStateException("unhandled log state '%s'" % state)
|
raise UnhandledLogStateException(f"unhandled log state '{state}'")
|
||||||
|
|
||||||
|
|
||||||
def get_log_info_structs(json_data):
|
def get_initializer_for_log(log, operator, json_data, log_format):
|
||||||
"""Return array of CTLogInfo initializers for the known logs."""
|
|
||||||
tmpl = Template(LOG_INFO_TEMPLATE)
|
|
||||||
initializers = []
|
|
||||||
for operator in json_data["operators"]:
|
|
||||||
operator_name = operator["name"]
|
|
||||||
for log in operator["logs"]:
|
|
||||||
log_key = base64.b64decode(log["key"])
|
log_key = base64.b64decode(log["key"])
|
||||||
|
operator_name = operator["name"]
|
||||||
operator_index = get_operator_index(json_data, operator_name)
|
operator_index = get_operator_index(json_data, operator_name)
|
||||||
state = list(log["state"].keys())[0]
|
state = list(log["state"].keys())[0]
|
||||||
timestamp_comment = log["state"][state]["timestamp"]
|
timestamp_comment = log["state"][state]["timestamp"]
|
||||||
timestamp = get_timestamp(timestamp_comment)
|
timestamp = get_timestamp(timestamp_comment)
|
||||||
state = map_state(state)
|
state = map_state(state)
|
||||||
if state is None:
|
if state is None:
|
||||||
continue
|
return None
|
||||||
is_test_log = "test_only" in operator and operator["test_only"]
|
is_test_log = "test_only" in operator and operator["test_only"]
|
||||||
prefix = ""
|
prefix = ""
|
||||||
suffix = ","
|
suffix = ","
|
||||||
@@ -173,6 +174,7 @@ def get_log_info_structs(json_data):
|
|||||||
suffix = ",\n#endif // DEBUG"
|
suffix = ",\n#endif // DEBUG"
|
||||||
num_spaces = len(str(timestamp)) - len(str(operator_index))
|
num_spaces = len(str(timestamp)) - len(str(operator_index))
|
||||||
spaces = " " * num_spaces
|
spaces = " " * num_spaces
|
||||||
|
tmpl = Template(LOG_INFO_TEMPLATE)
|
||||||
toappend = tmpl.substitute(
|
toappend = tmpl.substitute(
|
||||||
# Use json.dumps for C-escaping strings.
|
# Use json.dumps for C-escaping strings.
|
||||||
# Not perfect but close enough.
|
# Not perfect but close enough.
|
||||||
@@ -180,16 +182,35 @@ def get_log_info_structs(json_data):
|
|||||||
operator_index=operator_index,
|
operator_index=operator_index,
|
||||||
operator_comment=f"operated by {operator_name}".replace("/", "|"),
|
operator_comment=f"operated by {operator_name}".replace("/", "|"),
|
||||||
state=state,
|
state=state,
|
||||||
|
log_format=log_format,
|
||||||
timestamp=timestamp,
|
timestamp=timestamp,
|
||||||
spaces=spaces,
|
spaces=spaces,
|
||||||
timestamp_comment=timestamp_comment,
|
timestamp_comment=timestamp_comment,
|
||||||
# Maximum line width is 80.
|
# Maximum line width is 80.
|
||||||
indented_log_key="\n".join(
|
indented_log_key="\n".join([f' "{l}"' for l in get_hex_lines(log_key, 74)]),
|
||||||
[f' "{l}"' for l in get_hex_lines(log_key, 74)]
|
|
||||||
),
|
|
||||||
log_key_len=len(log_key),
|
log_key_len=len(log_key),
|
||||||
)
|
)
|
||||||
initializers.append(prefix + toappend + suffix)
|
return prefix + toappend + suffix
|
||||||
|
|
||||||
|
|
||||||
|
def get_log_info_structs(json_data):
|
||||||
|
"""Return array of CTLogInfo initializers for the known logs."""
|
||||||
|
initializers = []
|
||||||
|
for operator in json_data["operators"]:
|
||||||
|
if "logs" in operator:
|
||||||
|
for log in operator["logs"]:
|
||||||
|
initializer = get_initializer_for_log(
|
||||||
|
log, operator, json_data, "CTLogFormat::RFC6962"
|
||||||
|
)
|
||||||
|
if initializer:
|
||||||
|
initializers.append(initializer)
|
||||||
|
if "tiled_logs" in operator:
|
||||||
|
for log in operator["tiled_logs"]:
|
||||||
|
initializer = get_initializer_for_log(
|
||||||
|
log, operator, json_data, "CTLogFormat::Tiled"
|
||||||
|
)
|
||||||
|
if initializer:
|
||||||
|
initializers.append(initializer)
|
||||||
return initializers
|
return initializers
|
||||||
|
|
||||||
|
|
||||||
@@ -301,8 +322,34 @@ def patch_in_test_logs(json_data):
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
mozilla_test_operator_3 = {
|
||||||
|
"name": "Mozilla Test Org 3",
|
||||||
|
"id": max_id + 3,
|
||||||
|
"test_only": True,
|
||||||
|
"tiled_logs": [
|
||||||
|
{
|
||||||
|
"description": "Mozilla Test RSA Log 4",
|
||||||
|
# `openssl x509 -noout -pubkey -in <path/to/evroot.pem>`
|
||||||
|
"key": """
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtUmJXJ0AEI0Rofmfh6nj
|
||||||
|
0aXbXfrs8YjaV79kE2iPLORyLP8QkDjBdALJOipHPb0oau0/3NNjz1opFHcBvdgY
|
||||||
|
12Fb+TVr1dPIM2qqjAlxNooGw81EYbk+UUJOF0S7LqrUaqs4zhloIZYfh3FKFmNp
|
||||||
|
Pwl2HN9Na6El6s7HvicNOI94n2zfeK4xRO0oxF55KThjp6IqSJgKNqQOctV5ybkl
|
||||||
|
3/jHkzYv/WiXp8F1TF6XyWfD6t0aroqizM40igFpuA4ootcMGpYMbzNfLaCbm2Q/
|
||||||
|
Wr+6SeiqqYHpYOJ9h0gL3VXdlBf6GFCfu1VMz4GkOX6LqBKKNL3yeGXBieVzT7Ip
|
||||||
|
BQIDAQAB
|
||||||
|
""",
|
||||||
|
"state": {
|
||||||
|
"qualified": {
|
||||||
|
"timestamp": "2025-06-25T12:09:26Z",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
json_data["operators"].append(mozilla_test_operator_1)
|
json_data["operators"].append(mozilla_test_operator_1)
|
||||||
json_data["operators"].append(mozilla_test_operator_2)
|
json_data["operators"].append(mozilla_test_operator_2)
|
||||||
|
json_data["operators"].append(mozilla_test_operator_3)
|
||||||
|
|
||||||
|
|
||||||
def get_content_at(url):
|
def get_content_at(url):
|
||||||
@@ -348,7 +395,7 @@ def run(args):
|
|||||||
hash_alg = rsa.verify(json_text, signature, key)
|
hash_alg = rsa.verify(json_text, signature, key)
|
||||||
if hash_alg != "SHA-256":
|
if hash_alg != "SHA-256":
|
||||||
raise UnsupportedSignatureHashAlgorithmException(
|
raise UnsupportedSignatureHashAlgorithmException(
|
||||||
"unsupported hash algorithm '%s'" % hash_alg
|
f"unsupported hash algorithm '{hash_alg}'"
|
||||||
)
|
)
|
||||||
print("Writing output: ", args.json_file_out)
|
print("Writing output: ", args.json_file_out)
|
||||||
with open(args.json_file_out, "wb") as json_file_out:
|
with open(args.json_file_out, "wb") as json_file_out:
|
||||||
@@ -373,7 +420,7 @@ def parse_arguments_and_run():
|
|||||||
"Downloads the JSON file from the known source "
|
"Downloads the JSON file from the known source "
|
||||||
"of truth by default, but can also operate on a "
|
"of truth by default, but can also operate on a "
|
||||||
"previously-downloaded file. See https://certificate.transparency.dev/google/",
|
"previously-downloaded file. See https://certificate.transparency.dev/google/",
|
||||||
epilog="Example: ./mach python %s" % os.path.basename(sys.argv[0]),
|
epilog=f"Example: ./mach python {os.path.basename(sys.argv[0])}",
|
||||||
)
|
)
|
||||||
|
|
||||||
arg_parser.add_argument(
|
arg_parser.add_argument(
|
||||||
|
|||||||
Reference in New Issue
Block a user