インデックスにホストされた証明 <Index hosted attestations>¶
注釈
この仕様は、元々は PEP 740 で定義されました。
注釈
PEP 740 は、 HTML と JSON のインデックス API に対する変更を含みます。これらの変更は、 基本 API の下の シンプルなリポジトリ API や JSON シリアル化 の中で文書化されています。
仕様¶
エンドポイントの変更をアップロードする¶
重要
"レガシー <legacy>" なアップロード API は標準化されていません。どのように証明がアップロードされるのかについては、 PyPI のアップロード API に関するドキュメント を見てください。
証明オブジェクト¶
証明書 <attestation> オブジェクトは、いくつかの必須のキーを伴う JSON オブジェクトです; アプリケーションや署名者は、すべての明示的に列挙されたキーが提供されている限りは追加のキーを含めておいても構いません。証明書 <attestation> に要求されるレイアウトは、下記の仮想ソースコードの形で提供されています。
@dataclass
class Attestation:
version: Literal[1]
"""
The attestation object's version, which is always 1.
"""
verification_material: VerificationMaterial
"""
Cryptographic materials used to verify `envelope`.
"""
envelope: Envelope
"""
The enveloped attestation statement and signature.
"""
@dataclass
class Envelope:
statement: bytes
"""
The attestation statement.
This is represented as opaque bytes on the wire (encoded as base64),
but it MUST be an JSON in-toto v1 Statement.
"""
signature: bytes
"""
A signature for the above statement, encoded as base64.
"""
@dataclass
class VerificationMaterial:
certificate: str
"""
The signing certificate, as `base64(DER(cert))`.
"""
transparency_entries: list[object]
"""
One or more transparency log entries for this attestation's signature
and certificate.
"""
transparency_entries 内の各オブジェクト向けの完全なデータモデルは、 付属書 で提供されています。証明書 <attestation> オブジェクトは、一つ以上の透明ログエントリを含む べき であり、 (RFC 3161 タイムスタンプ局 <Time Stamping Authority> や Roughtime のような) 署名された時刻の他の情報源用の追加的なキーを含んでいても 構いません 。
証明書 <attestation> オブジェクトはバージョン付けされています; この PEP はバージョン 1 を指定しています。各バージョンは、不必要な暗号学的動揺を最低限に抑えるために、単一の暗号スイートに紐づけられます。バージョン 1 では、スイートは次のようなものです:
証明書は X.509 の証明書であるものとして指定されていて、 RFC 5280 のプロファイルを満足させます。
メッセージ署名のアルゴリズムは、公開鍵向けの P-256 曲線暗号と暗号学的ダイジェスト関数の SHA-256 を伴った ECDSA です。
将来の PEP では、新しいバージョン番号を選択することで、このスイート (および、証明書 <attestation> オブジェクトの全体の形式) を変更するかもしれません。
証明書 <attestation> ステートメントと署名生成¶
証明書 <attestation> ステートメント は、証明書オブジェクト (つまり、 envelope.statement) の内部で暗号学的に署名されているという宣言です。
証明書ステートメントは、 JSON 形式で v1 in-toto ステートメントオブジェクト として符号化されています。シリアライズされると、このステートメントは、正規化の必要を避けて不透明 <opaque> なバイナリの blob として取り扱われます。
v1 in-toto ステートメントであることに加えて、証明書ステートメントは次のような制約を受けます:
in-toto
subjectは、ただひとつのサブジェクトを含んでいなければ なりません 。subject[0].nameは配布物のファイル名で、正当な ソースコード配布物 か wheel 配布物 のファイル名で なければなりません 。subject[0].digestは、 SHA-256 ダイジェストを含んでいなければ なりません 。他のダイジェストがあっても 構いません 。ダイジェストは、16進数の文字列として表現されていなければ なりません 。次のような
predicateTypeの値がサポートされています:SLSA の起源:
https://slsa.dev/provenance/v1PyPI 公開証明書:
https://docs.pypi.org/attestations/publish/v1
このステートメントに対する署名は、application/vnd.in-toto+json の PAYLOAD_TYPE と JSON にエンコードされた上記のステートメントの PAYLOAD_BODY を伴った v1 DSSE signature protocol を使って構築されます。これ以外の PAYLOAD_TYPE は許されていません。
起源オブジェクト¶
インデックスは、シリアライズされた JSONオブジェクトの形式で検証することを助けることができるメタデータと共に、アップロードされた証明書を提供することでしょう。
これらの 起源オブジェクト は、上述の通り、 シンプルインデックス <Simple Index> と、 JSON ベースのシンプル API の両方を通じて利用することができるでしょうし、以下のレイアウトを持っていることでしょう。
{
"version": 1,
"attestation_bundles": [
{
"publisher": {
"kind": "important-ci-service",
"claims": {},
"vendor-property": "foo",
"another-property": 123
},
"attestations": [
{ /* attestation 1 ... */ },
{ /* attestation 2 ... */ }
]
}
]
}
あるいは、仮想ソースコードとして:
@dataclass
class Publisher:
kind: string
"""
The kind of Trusted Publisher.
"""
claims: object | None
"""
Any context-specific claims retained by the index during Trusted Publisher
authentication.
"""
_rest: object
"""
Each publisher object is open-ended, meaning that it MAY contain additional
fields beyond the ones specified explicitly above. This field signals that,
but is not itself present.
"""
@dataclass
class AttestationBundle:
publisher: Publisher
"""
The publisher associated with this set of attestations.
"""
attestations: list[Attestation]
"""
The set of attestations included in this bundle.
"""
@dataclass
class Provenance:
version: Literal[1]
"""
The provenance object's version, which is always 1.
"""
attestation_bundles: list[AttestationBundle]
"""
One or more attestation "bundles".
"""
versionは1です。証明書オブジェクトと似て、起源オブジェクトはバージョン付けされていて、この PEP ではバージョン1だけを定義しています。attestation_bundlesは、証明書 <attestation> の "バンドル <bundle>" をひとつ以上含む形で JSON 配列に存在するように 要求されて います。それぞれのバンドルは、 (信頼ある公開 <Trusted Publishing> のアイデンティティのような) 署名側のアイデンティティに対応し、証明書オブジェクトを一つ以上含みます。Publisherモデルの中で註記されたように、AttestationBundle.publisherオブジェクトは、それぞれ、その信頼された公開者 <Trusted Publisher> に特有のもので、少なくとも以下のものを含まなければなりません:kindキー、これは、信頼された公開者の種類を一意に特定する JSON 文字列で なければなりません 。claimsキー、これは、信頼された公開者の認証の際にインデックスが記録したコンテキストに特有の主張 <claims> を含む JSON オブジェクトで なければなりません 。
公開者オブジェクト <piblisher object> の他のすべてのキーは、公開者に特有のものです。
証明書オブジェクトの各配列は、 エンドポイントの変更をアップロードする と 起源オブジェクトに対する変更 の中に記述されているように、アップロードの時点の
attestationsフィールドを通じてアップロードされたものから供給されるattestations配列のスーパーセットです。
起源オブジェクトに対する変更¶
起源オブジェクト <Provenance objects> は、変更不可能なものでは ありません し、時間の経過とともに変化しても構いません。起源オブジェクトへの変更の理由は、次のものを含みますが、これに限るわけではありません:
既存の署名アイデンティティ <signing identity> 用の新しい証明書 <attestation> の追加: インデックスは、既存の署名アイデンティティによる (既にアップロードされたファイル群よりも新しいバージョンの証明書のような) 追加の証明書を許容することを選択しても 構いません 。
新しい署名アイデンティティの追加と関連する証明書: インデックスは、 (第3者の監査人やインデックスそれ自体のような) ファイルのアップロードを行った主体とは異なるところからの証明書をサポートすることを選択しても 構いません 。これらの証明書は、インデックスが起源オブジェクトにそれらを 遡求的に 挿入することを要求して、非同期的に処理されるでしょう。
証明書検証¶
配布物ファイルに対する証明書オブジェクトを検証することは、以下のそれぞれの検証を要求します:
versionが1であること。検証者は他のあらゆるバージョンを拒否しなければ なりません 。verification_material.certificateは、 (検証しているクライアントの中に既に存在する信頼のルートのような) 天与の <a priori> 信頼された権威者によって発行されたもので、正当な署名証明書です。verification_material.certificateは、パッケージを公開した信頼された公開者の機械のアイデンティティのような、適切な署名対象を識別します。envelope.statementは、配布物のファイル名とその内容に合致しなければ ならない 対象 <subject> とダイジェストを伴う、正当な in-toto v1 ステートメントです。配布物のファイル名については、ステートメントの対象は同一かもしれませんが標準化されたものであるため、適切なソースコード配布物か wheel のファイル名フォーマットをパースすることで合致検証が行われなければ なりません 。envelope.signatureは、 v1 DSSE 署名プロトコル を通じて再構成されたもので、verification_material.certificateに関係するenvelope.statementに対する正当な署名です。
上記の要求されたステップ群に加えて、検証者は、例えば少なくとも一つの透過ログエントリを要求したりエントリ群に対する閾値を設けたりというポリシーに基づいて verification_material.transparency_entries を追加で検証しても 構いません 。透過エントリを検証する時には、検証者は、それぞれのエントリの包括時刻 <inclusion time> が署名者証明書の有効期間内にあることを確認しなければ なりません 。
補遺: 透過ログエントリのデータモデル¶
この補遺には、証明書オブジェクト内の透過ログエントリに関する仮想ソースコードの形でデータモデルが含まれています。それぞれの透過ログエントリは、署名付き包括時刻 <inclusion time> の源泉として働き、オンラインでもオフラインでも検証することができます。
@dataclass
class TransparencyLogEntry:
log_index: int
"""
The global index of the log entry, used when querying the log.
"""
log_id: str
"""
An opaque, unique identifier for the log.
"""
entry_kind: str
"""
The kind (type) of log entry.
"""
entry_version: str
"""
The version of the log entry's submitted format.
"""
integrated_time: int
"""
The UNIX timestamp from the log from when the entry was persisted.
"""
inclusion_proof: InclusionProof
"""
The actual inclusion proof of the log entry.
"""
@dataclass
class InclusionProof:
log_index: int
"""
The index of the entry in the tree it was written to.
"""
root_hash: str
"""
The digest stored at the root of the Merkle tree at the time of proof
generation.
"""
tree_size: int
"""
The size of the Merkle tree at the time of proof generation.
"""
hashes: list[str]
"""
A list of hashes required to complete the inclusion proof, sorted
in order from leaf to root. The leaf and root hashes are not themselves
included in this list; the root is supplied via `root_hash` and the client
must calculate the leaf hash.
"""
checkpoint: str
"""
The signed tree head's signature, at the time of proof generation.
"""
cosigned_checkpoints: list[str]
"""
Cosigned checkpoints from zero or more log witnesses.
"""