As Apple looks at its CT Log operations and its CT Log List Schema, we note that there is room for improved clarity in expressing some CT Log statuses. One such change which we’d like to make is to add an “Expired” state for CT Logs/Log Shards, used to denote when a previously Usable or Qualified Log has passed its temporal interval’s end timestamp. Since temporal intervals are enforced locally by clients, the net behavior would remain unchanged and this status would primarily ensure the log's state reflects this current behavior. In a similar way to Rejected logs, Expired logs would be trimmed from local relying party log lists.
The proposed updated schema is below. At this time, we’d like to know if this change would cause issues for ecosystem participants and whether there are any concerns with or comments on this change.
{
"type": "object",
"required": [
"version",
"assetVersion",
"operators"
],
"definitions": {
"state": {
"type": "object",
"properties": {
"timestamp": {
"description": "The time at which the log entered this state.",
"examples": [
"2018-01-01T00:00:00Z"
],
"format": "date-time",
"type": "string"
},
"version": {
"description": "The log list version in which the log entered this state.",
"minimum": 1,
"type": "string"
}
},
"required": [
"timestamp",
"version"
]
}
},
"properties": {
"assetVersion": {
"title": "Asset version containing this log list",
"description": "Asset version in which this log list was included",
"minimum": 1,
"type": "number"
},
"version": {
"type": "string",
"title": "Version of this log list",
"description": "The version will change whenever a change is made to any part of this log list.",
"examples": [
"1",
"1.0.0",
"1.0.0b"
]
},
"operators": {
"title": "CT log operators",
"description": "People/organizations that run Certificate Transparency logs.",
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"email",
"logs"
],
"properties": {
"name": {
"title": "Name of this log operator",
"type": "string"
},
"email": {
"title": "CT log operator email addresses",
"description": "The log operator can be contacted using any of these email addresses.",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"format": "email"
}
},
"logs": {
"description": "Details of Certificate Transparency logs run by this operator.",
"type": "array",
"items": {
"type": "object",
"required": [
"key",
"log_id",
"mmd",
"url",
"state"
],
"properties": {
"description": {
"title": "Description of the CT log",
"description": "A human-readable description that can be used to identify this log.",
"type": "string"
},
"key": {
"title": "The public key of the CT log",
"type": "string"
},
"log_id": {
"title": "The SHA-256 hash of the CT log's public key, base64-encoded",
"type": "string",
"minLength": 44,
"maxLength": 44
},
"mmd": {
"title": "The Maximum Merge Delay, in seconds",
"type": "number",
"minimum": 1,
"default": 86400
},
"url": {
"title": "The base URL of the CT log's HTTP API",
"type": "string",
"format": "uri",
"examples": [
]
},
"dns": {
"title": "The domain name of the CT log's DNS API",
"type": "string",
"format": "hostname",
"examples": [
]
},
"temporal_interval": {
"description": "The log will only accept certificates that expire (have a NotAfter date) between these dates.",
"type": "object",
"required": [
"start_inclusive",
"end_exclusive"
],
"properties": {
"start_inclusive": {
"description": "All certificates must expire on this date or later.",
"type": "string",
"format": "date-time",
"examples": [
"2018-01-01T00:00:00Z"
]
},
"end_exclusive": {
"description": "All certificates must expire before this date.",
"type": "string",
"format": "date-time",
"examples": [
"2019-01-01T00:00:00Z"
]
}
}
},
"log_type": {
"description": "The purpose of this log, e.g. test.",
"type": "string",
"enum": [
"prod",
"test"
]
},
"state": {
"title": "The state of the log from the log list distributor's perspective.",
"type": "object",
"properties": {
"pending": {
"$ref": "#/definitions/state"
},
"qualified": {
"$ref": "#/definitions/state"
},
"usable": {
"$ref": "#/definitions/state"
},
"readonly": {
"allOf": [
{
"$ref": "#/definitions/state"
},
{
"required": [
"final_tree_head"
],
"properties": {
"final_tree_head": {
"description": "The tree head (tree size and root hash) at which the log was made read-only.",
"type": "object",
"required": [
"tree_size",
"sha256_root_hash"
],
"properties": {
"tree_size": {
"type": "number",
"minimum": 0
},
"sha256_root_hash": {
"type": "string",
"minLength": 44,
"maxLength": 44
}
}
}
}
}
]
},
"retired": {
"$ref": "#/definitions/state"
},
"rejected": {
"$ref": "#/definitions/state"
},
"expired": {
"$ref": "#/definitions/state"
}
},
"oneOf": [
{
"required": [
"pending"
]
},
{
"required": [
"qualified"
]
},
{
"required": [
"usable"
]
},
{
"required": [
"readonly"
]
},
{
"required": [
"retired"
]
},
{
"required": [
"rejected"
]
},
{
"required": [
"expired"
]
}
]
}
}
}
}
}
}
}
}
}