Compliance kanıtı attestation'ı, sürüm 1.
https://attestkeep.com/attestation/compliance-evidence/v1, Attestkeep'in bir compliance raporu için imzaladığı her attestation'ın predicateType'ıdır. Bu adrese bir belgeden geldiyseniz bu sayfa o belgenin tanımıdır: iddia, bütün alanlar, envelope, imzalanan kodlama ve doğrulayabileceğiniz gerçek bir örnek.
Öne sürülen iddia
Tek cümleyle: bu compliance raporunu bu kurulum üretti ve rapor o zamandan beri değiştirilmedi. İddianın tamamı budur; aşağıdaki her şey bundan çıkar.
İddia, kendi tasarladığımız bir imza şemasıyla değil, supply chain dünyasının bu iş için zaten kullandığı formatla taşınır: Ed25519 ile imzalanmış bir DSSE envelope içinde bir in-toto statement. Bu bilinçli bir tercih: yalnızca bizim doğrulayabileceğimiz bir format bizi darboğaza çevirirdi; belgenin değeri tam olarak, denetçinin onu biz orada olmadan kontrol edebilmesinden gelir. İmzalama anahtarı kurulumun içinde üretilir ve oradan hiç çıkmaz; dünyanın güvenmesi istenen tek şey anahtarın public kısmıdır.
Statement ve subject'i
Envelope'un payload'u, sürüm 1 bir in-toto statement'tır. Dış alanları şunlardır:
| Alan | Tür | Anlamı |
|---|---|---|
_type | string | Her zaman https://in-toto.io/Statement/v1. |
subject | array | İddianın konusu olan raporu belirten tek bir resource descriptor: name rapor kimliğidir; digest.sha256 ise üretilen baytların birebir SHA-256 değeridir ve sha256: öneki olmadan 64 küçük harf hex karakter olarak yazılır. |
predicateType | string | Her zaman https://attestkeep.com/attestation/compliance-evidence/v1, yani bu sayfanın adresi. |
predicate | object | İddianın kendisi; her alan bir sonraki bölümde tanımlanır. |
Statement bir belge hakkındadır, bu yüzden subject de o belgedir. Raporun kendisi attestation'ın içinde taşınmaz ve bu bilinçli bir karardır: rapor büyüktür ve okuyucunun elinde PDF ya da CSV hâli olabilir. Kanıtlanması gereken şey, okuyucunun elindeki kopyanın imzalanan kopya olduğudur. Digest bu soruyu baytların her kopyası için cevaplar; attestation'ın içine konmuş bir kopya ise yalnızca o kopya için cevaplardı.
Framework ve denetim dönemi, subject ile birlikte imzanın içindedir. Aynı dönem iki ayrı framework'e göre değerlendirilirse iki ayrı belge çıkar ve okuyucu bunlardan birini öbürünün etiketiyle sunamamalıdır. Statement'taki hiçbir şey (subject, digest, dönem, framework, zaman damgaları) imzadan sonra doğrulamayı bozmadan değiştirilemez.
Predicate alanları
İsteğe bağlı alanlar boşsa JSON'a hiç yazılmaz, yer tutucu olarak da yazılmaz. Kurulumun elinde olmayan bir zaman damgası uydurma bir tarihle değil, boş string olarak yazılır.
| Alan | Tür | Anlamı |
|---|---|---|
report_id | string | Belgenin kimliği; raporun üzerinde basılı kimlikle aynıdır, böylece elinizdeki attestation'ı elinizdeki raporla bir bakışta eşleştirebilirsiniz. Subject'teki name değerini tekrarlar. |
framework | string | Raporun hazırlanırken dayandığı compliance eşlemesi, örneğin soc2. İmzanın içindedir; böylece bir framework'ün raporu başka bir framework'ün etiketiyle sunulamaz. |
period | object | Raporun kapsadığı denetim aralığı. |
period.start, period.end | string | UTC'ye çevrilmiş RFC 3339 zaman damgaları. Aktarımda string olarak taşınır, çünkü imzalanan şey birebir baytlardır. |
installation | object | İmzalayanı cluster'ı tarif etmeden tanımlar. |
installation.fingerprint | string | Lisansın bağlı olduğu opak cluster kimliği: topoloji ya da ad içermeyen, müşterinin binasından çıkan bir belgeye konmasına itiraz edeceği hiçbir şeyi taşımayan bir hash. |
installation.license_id | string, isteğe bağlı | Sertifikayı verenin, kurulumun o sırada lisanslı olduğunu teyit etmesini sağlar; "bu dosyaya dokunulmamış" ile "gerçek bir kurulumdan geldi" arasındaki bağ budur. |
installation.binding_id | string, isteğe bağlı | Bu kurulumun aktive edildiği lisans bağı; aynı teyit için kullanılır. |
generated_at | string | Kurulumun raporu ürettiği an, kendi saatine göre; RFC 3339 UTC. İmzalayanın beyanıdır, kanıt değildir: belgeyi güvenilir bir saate bağlayan hiçbir şey yoktur, buna ihtiyacı olan okuyucu bu kanıtı başka bir yerden almalıdır. |
generated_by | string, isteğe bağlı | Raporu isteyen hesap, user:<account id> biçiminde. 1.2.0'dan beri hiçbir zaman ad ya da e-posta adresi değildir; kurulumu yöneten kişi, talep olursa kimliği kendi console'unun audit log'undan çözer. |
generator | object | Raporu üreten yazılım. |
generator.name, generator.version | string | Hangi release'in compliance eşlemelerinin geçerli olduğu. Framework'ler daha dikkatli okundukça eşlemeler değişir; hangi okumayı kullandığını söylemeyen bir kanıt sonradan yeniden incelenemez. |
DSSE envelope
Statement şu şekilde bir DSSE envelope içinde taşınır:
{
"payload": "<standard base64 of the statement JSON>",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{ "keyid": "ak-…", "sig": "<base64 of an Ed25519 signature>" }
]
}payload, marshal edilmiş statement baytlarının birebir, padding'li standart base64 karşılığıdır. Statement bir kez serialize edilir: imzalanan baytlar, iletilen baytlarla aynıdır.payloadTypeda imzalanan verinin parçasıdır (aşağıdaki kodlamaya bakın); bu yüzden bir in-toto statement üzerindeki imza, aynı baytların başka bir şey olarak okunmuş hâlinin imzası gibi sunulamaz.sig,PAE(payloadType, payload)üzerine atılmış bir Ed25519 imzasıdır (RFC 8032); base64 string'in değil, pre-authentication encoding'in üzerine atılır.keyidpublic key'den türetilir:"ak-"ve ardından 32 baytlık anahtarın SHA-256 değerinin ilk 16 hex karakteri. Türetildiği için belirttiği anahtarla çelişemez; ama yalnızca bir ipucudur. Doğrulayıcı, envelope'un söylediği bir anahtarla değil, zaten güvendiği bir anahtarla kontrol etmelidir.- Bir envelope birden fazla imza taşıyabilir. Doğrulayıcı her girdiyi güvendiği anahtarla dener; herhangi biri doğrulanırsa envelope'u kabul eder.
PAE kodlaması
İmzalanan şey, payload'un türüyle birlikte oluşturulan pre-authentication encoding'idir:
PAE(type, body) = "DSSEv1" SP LEN(type) SP type SP LEN(body) SP bodyBurada SP tek bir boşluk, LEN ise ondalık ASCII olarak yazılmış bayt uzunluğudur. Uzunluklar karakter değil bayt olarak sayılır. Örneğin PAE("http://example.com/HelloWorld", "hello world"), DSSEv1 29 http://example.com/HelloWorld 11 hello world bayt dizisidir.
DSSE'nin güvenliğinin tamamı bu fikre dayanır. Yalnızca payload imzalansaydı, bir in-toto statement üzerine atılmış imza, farklı bir payloadType altında tesadüfen aynı baytlara sahip başka bir şeyin imzası gibi sunulabilirdi. PAE ikisini birbirine bağlar; uzunluk önekleri sayesinde hiçbiri öbürünün parçası gibi gösterilemez.
Sertifika zinciri
Envelope'un imzası raporun değişmediğini kanıtlar ve bir anahtarı belirtir. Ama o anahtarın kime ait olduğunu tek başına kanıtlayamaz: public key'i belgeyi getiren kişiden alan bir doğrulayıcı yalnızca iç tutarlılığı kanıtlar. Bu boşluğu lisans sertifikası kapatır. Sertifika, Attestkeep'in her lisanslı kurulum için imzaladığı bir belgedir ve kurulumun kanıt imzalama anahtarını imzanın içinde taşır; böylece tek bir Attestkeep anahtarına güvenen okuyucu, herhangi bir kurulumdan gelen raporu doğrulayabilir:
Attestkeep kök anahtarı
└─ imzalar → lisans sertifikası (compact JWT)
└─ cnf.jwk gösterir → kurulumun kanıt anahtarı
└─ imzalar → DSSE envelope
└─ subject digest'i sabitler → raporKök anahtar. Bu sayfadan TLS üzerinden alınan bu değer, zincirin tek güven çapasıdır:
kid: ak1
ed25519: e287aabe4712197cfa5b6fdf9ea8f2d7f0333ce16ca69aac7e4a3f1e84c04179Sertifika bir compact JWT'dir (RFC 7515): base64url(header) "." base64url(payload) "." base64url(signature); base64url padding'siz kullanılır (RFC 4648 bölüm 5, = yok). Header {"alg":"EdDSA","typ":"JWT","kid":"ak1"} şeklindedir. Doğrulayıcı EdDSA dışındaki her alg değerini reddetmelidir; böylece klasik JWT downgrade saldırıları (alg=none, algorithm confusion) yapı gereği dışarıda kalır. İmza, header_b64 "." payload_b64 ASCII baytları üzerine atılmış bir Ed25519 imzasıdır.
Zincir doğrulayıcının okuduğu payload alanları (bilinmeyen alanlar yok sayılmalıdır; veren taraf claim ekleyebilir):
| Alan | Tür | Anlamı |
|---|---|---|
sub | string | Sertifikanın verildiği lisans kimliği. |
fpr | string | Lisansın bağlı olduğu cluster parmak izi; predicate'teki installation.fingerprint değeri buna eşit olmalıdır. |
plan | string | Plan kodu; zincir doğrulayıcı için bilgi amaçlıdır. |
iat, exp | number | Verilme ve bitiş zamanı, unix saniyesi. exp 0 ise sertifikanın süresi dolmaz. |
jti | string | Sertifikanın seri numarası. |
cnf.jwk | string | RFC 7800'deki confirmation claim: kurulumun Ed25519 kanıt public key'i, tam 64 hex karakter. İç içe bir JWK nesnesi değil, hex olarak kodlanmış ham 32 bayttır. Bu alanı olmayan bir sertifika hiçbir anahtara kefil olmaz ve zincire çapa olamaz. |
Bir raporu zincir üzerinden doğrulamak için:
- Sertifikayı
.karakterinden tam üç parçaya bölün; header'ı decode edin vealgdeğeriEdDSAdeğilse reddedin. header_b64 "." payload_b64ASCII baytları üzerindeki Ed25519 imzasını yukarıdaki kök anahtarla doğrulayın.- Payload'u decode edin ve kurulumun kanıt anahtarı olan
cnf.jwkdeğerini okuyun. - DSSE envelope'u bu anahtarla, yukarıdaki bölümlerde anlatıldığı şekilde doğrulayın.
- Çapraz kontrol: statement'taki
predicate.installation.fingerprintdeğeri sertifikadakifprdeğerine eşit olmalıdır. Bu adım olmazsa gerçek bir sertifika, başka bir kurulumdan gelen gerçek bir envelope'un yanında sunulabilir.installation.license_idvarsa vesubdeğerinden farklıysa okuyucuyu uyarın.
Sürenin dolmuş olması ret sebebi değil, bir bilgidir. Sertifikalar otuz günde bir yenilenir; geçen çeyreğe ait bir rapora, o dönem geçerli olan sertifika kefil olur. Süresi dolmuş sertifikaları reddetmek bütün eski raporları doğrulanamaz hâle getirirdi. Doğrulayıcı, süresi dolmuş bir sertifikanın tarihini göstermeli ve kararı okuyucuya bırakmalıdır.
Tam bir örnek
Bu envelope referans imzalayıcıyla üretildi. Bilerek herkese açık bir test anahtarıyla imzalanmıştır (Ed25519 seed'i 0x01 ile 0x20 arasındaki baytlardır); yani gerçek bir raporun kaynağını değil, formatı gösterir. Gerçek attestation'lar her kurulumun içinde üretilen ve kurulumdan hiç çıkmayan bir anahtarla imzalanır.
{
"payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicnB0LTlmMmM3YTQxZDBiODNlNTYiLCJkaWdlc3QiOnsic2hhMjU2IjoiNzQ3YjgzZWNkMTY2OTEyNjk2NmVlNjAyZTM3MjI0NTE2Y2M5YmMyZGQ5NWFhZWJlNDIwZWQxY2IzNGVkZWMwYyJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2F0dGVzdGtlZXAuY29tL2F0dGVzdGF0aW9uL2NvbXBsaWFuY2UtZXZpZGVuY2UvdjEiLCJwcmVkaWNhdGUiOnsicmVwb3J0X2lkIjoicnB0LTlmMmM3YTQxZDBiODNlNTYiLCJmcmFtZXdvcmsiOiJzb2MyIiwicGVyaW9kIjp7InN0YXJ0IjoiMjAyNi0wNy0wMVQwMDowMDowMFoiLCJlbmQiOiIyMDI2LTA3LTMxVDIzOjU5OjU5WiJ9LCJpbnN0YWxsYXRpb24iOnsiZmluZ2VycHJpbnQiOiIzZjdiMWE5ZTVjMmQ4ZjA0YTZiM2UxYzdkOTA1MmU4YTFiNGY2YzNkN2U5YTBiMmM0ZDZlOGYwYTFiM2M1ZDdlIiwibGljZW5zZV9pZCI6ImxpYy03YzMxZjBkMiIsImJpbmRpbmdfaWQiOiJiaW5kLWE5NGUyYzE3In0sImdlbmVyYXRlZF9hdCI6IjIwMjYtMDgtMDFUMDY6MDA6MDBaIiwiZ2VuZXJhdGVkX2J5IjoidXNlcjp1c3ItN2QyYzFhOWU0YjNmNWM2ZDhlMGYxYTJiIiwiZ2VuZXJhdG9yIjp7Im5hbWUiOiJhdHRlc3RrZWVwIiwidmVyc2lvbiI6IjAuMS4wIn19fQ==",
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"keyid": "ak-65b60673d6ed884b",
"sig": "DUTZfcrSxs8IuyoPBcBOVa10sgg5Yy2/QQkCF8t0RFa2U+sjp5NGfVwHprbZ30dNtCogfZeexpLR8EYKsEWKCQ=="
}
]
}Payload şu statement'a çözülür:
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "rpt-9f2c7a41d0b83e56",
"digest": {
"sha256": "747b83ecd1669126966ee602e37224516cc9bc2dd95aaebe420ed1cb34edec0c"
}
}
],
"predicateType": "https://attestkeep.com/attestation/compliance-evidence/v1",
"predicate": {
"report_id": "rpt-9f2c7a41d0b83e56",
"framework": "soc2",
"period": {
"start": "2026-07-01T00:00:00Z",
"end": "2026-07-31T23:59:59Z"
},
"installation": {
"fingerprint": "3f7b1a9e5c2d8f04a6b3e1c7d9052e8a1b4f6c3d7e9a0b2c4d6e8f0a1b3c5d7e",
"license_id": "lic-7c31f0d2",
"binding_id": "bind-a94e2c17"
},
"generated_at": "2026-08-01T06:00:00Z",
"generated_by": "user:usr-7d2c1a9e4b3f5c6d8e0f1a2b",
"generator": {
"name": "attestkeep",
"version": "0.1.0"
}
}
}Onu doğrulayan public key, doğrulayıcının beklediği biçimde:
79b5562e8fe654f94078b112e8a98ba7901f853ae695bed7e0e3910bad049664Bunu dokümantasyondaki yalnızca standart kütüphane kullanan script'le ya da herhangi bir DSSE implementasyonuyla kontrol edin: doğrulama geçer, payload'da tek bir karakteri değiştirdiğinizde ise başarısız olur. Tarayıcıdaki doğrulayıcı tek başına bir envelope ve anahtar değil, teslim edilen paketi alır; spesifikasyon okuyan biri için değil, elinde gerçek bir arşiv olan denetçi için yapılmıştır.
Attestation doğrulama
Artan bağımsızlık sırasıyla üç yol:
- bu sitedeki doğrulama sayfası; tamamen tarayıcınızda çalışır ve hiçbir yere hiçbir şey göndermez;
- DSSE ve in-toto destekleyen herhangi bir araç; formatta tescilli hiçbir parça yoktur;
- herhangi bir dilde bir düzine satırlık kendi kodunuz: lisans sertifikasını kök anahtarla doğrulayın, kurulumun anahtarını
cnf.jwkalanından alın, payload'u base64'ten decode edin, PAE'yi oluşturun, Ed25519 imzasını o anahtarla doğrulayın ve statement'ı ancak bundan sonra okuyun.
Hangisini seçerseniz seçin güven çapası aynıdır: kurulumun anahtarına yukarıda anlatıldığı gibi lisans sertifikası üzerinden kefil olan Attestkeep kök anahtarı. Belgenin kendisinden alınan bir anahtar asla çapa olamaz, çünkü belgedeki keyid bir kimlik bilgisi değil, yalnızca bir etikettir. Raporu getiren kişiden güvenerek alınan bir anahtar da çapa olamaz. Elden teslim edilen bir anahtarla envelope yine doğrulanır, ama bu yalnızca iç tutarlılığı kanıtlar, kaynağı kanıtlamaz. Sınırlar da aynıdır: geçerli bir zincir, belgenin değişmediğini ve onu hangi kurulumun imzaladığını kanıtlar. Hukuki anlamda elektronik imza değildir ve imzanın ne zaman atıldığını kanıtlamaz; generated_at ve dönem, kurulumun kendi beyanıdır. İki sınır da doğrulama sayfasında ayrıntılı olarak yazılıdır.
Son güncelleme: 29 Ağustos 2026