Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

Commit

Permalink
Remove issuer and refactor metadata in Claim (#139)
Browse files Browse the repository at this point in the history
* Remove issuer and rename metadata to validity
  • Loading branch information
rbehjati authored Oct 7, 2022
1 parent 9001b0c commit 878e8e1
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 105 deletions.
12 changes: 5 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Mount bazel cache
uses: actions/cache@v1
with:
path: "/home/runner/.cache/bazel"
path: '/home/runner/.cache/bazel'
key: bazel

- name: Install bazelisk
Expand All @@ -28,8 +28,6 @@ jobs:
mkdir -p "${GITHUB_WORKSPACE}/bin/"
mv bazelisk-linux-amd64 "${GITHUB_WORKSPACE}/bin/bazel"
chmod +x "${GITHUB_WORKSPACE}/bin/bazel"
- name: Install mcpp #mcpp is a dependency of Souffle
run: sudo apt-get install -y mcpp
- name: Build
run: |
Expand All @@ -47,7 +45,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "=1.18.4"
go-version: '=1.18.4'
- name: Run go test
run: |
go test -coverpkg=./... -coverprofile coverage.out ./pkg/... ./internal/...
Expand All @@ -71,7 +69,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "=1.18.4"
go-version: '=1.18.4'
- name: Run go fmt
run: |
./scripts/formatting.sh
Expand All @@ -82,7 +80,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "=1.18.4"
go-version: '=1.18.4'
- name: Run golint
run: |
go install github.com/golangci/golangci-lint/cmd/[email protected]
Expand All @@ -94,7 +92,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "=1.18.4"
go-version: '=1.18.4'
- name: Run go vet
run: |
go vet ./...
94 changes: 34 additions & 60 deletions docs/claim-transparency.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ different types of claims.

"predicateType": "https://github.com/project-oak/transparent-release/schema/claim/v1",
"predicate": {
"issuer": {
"id": "<URI>"
},
"claimType": "<URI>",
"metadata": {
"issuedOn": "<TIMESTAMP>",
"validFrom": "<TIMESTAMP>",
"expiresOn": "<TIMESTAMP>",
"issuedOn": "<TIMESTAMP>",
"validity": {
"notBefore": "<TIMESTAMP>",
"notAfter": "<TIMESTAMP>",
},
"claimSpec": { /* object */ },
"evidence": [
Expand All @@ -60,27 +57,18 @@ This section describes the semantics of each field in the claim format:
- **subject** _(array of objects, required)_:
Set of artifacts (e.g., source code, or some binary) that the claim applies to.
- **subject[*].digest** and **subject[*].name** as defined by Statement in the in-toto standard.
- **issuer** _(object, required)_:
Identifies the entity (person, organization, or an automated tool) that reviewed/audited/examined
the artifact in the subject of this claim.
- **issuer.id** _(string ([TypeURI](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#TypeURI)), required)_:
URI indicating the issuer’s identity (e.g., mailto:[email protected]).
- **claimType** _(string ([TypeURI](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#TypeURI)), required)_:
URI indicating what type of claim was issued. It determines the meaning of claimSpec and evidence below.
- **metadata** _(object, required)_:
Additional details about the claim.

- **metadata.issuedOn** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp of when the assessment of the artifact was performed. In most cases, the
assessment involves manually auditing or reviewing some source code. The timestamp in this case
does not have to be the accurate moment the review process started, but only the date on which
the review was done.
- **metadata.validFrom** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp from which the claim is effective, and the artifact is endorsed for use. In most
cases, it is the same as issuedOn timestamp, but can be any time after that.
- **metadata.expiresOn** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp of when the artifact is no longer endorsed for use. This, combined with the
validFrom field, is particularly useful for implementing passive revocation.
- **issuedOn** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp at which this claims was generated.
- **validity** _(object, required)_:
Validity duration of the claim. It enables implementing passive revocation.

- **validity.notBefore** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp from which the claim is effective, and the artifact is endorsed for use. Must be
equal or after the issuedOn timestamp.
- **validity.notAfter** _(string ([Timestamp](https://github.com/in-toto/attestation/blob/main/spec/field_types.md#Timestamp)), required)_:
The timestamp of when the artifact is no longer endorsed for use.

- **claimSpec** _(object, optional)_:
Gives a detailed description of the claim, and the steps that were taken to perform the assessment
Expand All @@ -92,7 +80,8 @@ This section describes the semantics of each field in the claim format:
limitations & threats, and the additional material that was used to perform the assessment, for
instance design docs may be used as one input. Such materials should not be included in the
subject, unless the review is particularly about that material (e.g., a design doc).
- The content of a cargo-crev review.
- The content of a [cargo-crev](https://github.com/crev-dev/cargo-crev) review, or an
[audit recorded via cargo vet](https://mozilla.github.io/cargo-vet/recording-audits.html).
- A link to a report similar to this security review of a cryptographic Rust crate, identified by
its URI and digest.
- An auto-generated report, for instance a fuzz testing report from ClusterFuzz.
Expand Down Expand Up @@ -141,7 +130,6 @@ provenance statement.

| Field in a Claim statement | Field in a SLSA provenance | Comments |
|:----------------|:---------------|:-----------------------------------------------------------|
| issuer | builder | SLSA distinguishes between the builder and signer. In the context of claims, we expect the issuer and the signer to be the same entity.|
| claimType | buildType | Both define the meanings of the other fields in the predicate.|
| claimSpec | buildConfig | Both provide a flexible way of supporting different types of content (claims, and build processes).|
| evidence | materials | Optional list of (a subset of ) additional artifacts that influenced the statement. |
Expand Down Expand Up @@ -182,14 +170,11 @@ include a reference to a Rekor log entry corresponding to the provenance.

"predicateType": "https://github.com/project-oak/transparent-release/schema/claim/v1",
"predicate": {
"issuer": {
"id": "mailto:[email protected]"
},
"claimType": "https://gh/project-oak/transparent-release/schema/endorsement/v2",
"metadata": {
"issuedOn": "2022-06-08T10:20:50.32Z",
"validFrom": "2022-06-08T10:20:50.32Z",
"expiresOn": "2022-06-09T10:20:50.32Z"
"issuedOn": "2022-06-08T10:20:50.32Z",
"validity": {
"notBefore": "2022-06-08T10:20:50.32Z",
"notAfter": "2022-06-09T10:20:50.32Z"
},
"evidence": [
{
Expand All @@ -206,10 +191,8 @@ include a reference to a Rekor log entry corresponding to the provenance.

A more sophisticated claimType for endorsements would have a non-empty claimSpec, containing a
specification of the policy that was checked before issuing the endorsement statement.
Authorization logic is a good candidate for providing a specification of such a policy. The
claimSpec may in addition contain a signature from the tool that verified the policy and issued the
endorsement statement. This is if we want to keep the product team as the issuer. Otherwise, we
could use the tool as the issuer and the signer of the entire endorsement statement.
Authorization logic is a good candidate for providing a specification of such a policy. In this
case the tool that verified the policy and generated the claim will as well sign the claim.

```json
{
Expand All @@ -223,14 +206,11 @@ could use the tool as the issuer and the signer of the entire endorsement statem

"predicateType": "https://gh/project-oak/transparent-release/schema/claim/v1",
"predicate": {
"issuer": {
"id": "mailto:[email protected]"
},
"claimType": "https://gh/project-oak/transparent-release/schema/endorsement/v3",
"metadata": {
"issuedOn": "2022-06-08T10:20:50.32Z",
"validFrom": "2022-06-08T10:20:50.32Z",
"expiresOn": "2022-06-09T10:20:50.32Z",
"issuedOn": "2022-06-08T10:20:50.32Z",
"validity": {
"notBefore": "2022-06-08T10:20:50.32Z",
"notAfter": "2022-06-09T10:20:50.32Z",
},
"claimSpec": {
"verification": "<The provenance verification policy, in authorization logic, that was verified as a precondition for issuing this endorsement statement.>",
Expand Down Expand Up @@ -272,14 +252,11 @@ the report.

"predicateType": "https://gh/project-oak/transparent-release/schema/claim/v1",
"predicate": {
"issuer": {
"id": "mailto:[email protected]"
},
"claimType": "https://github.com/project-oak/oak/claim/v1",
"metadata": {
"issuedOn": "2022-06-08T10:20:50.32Z",
"validFrom": "2022-06-08T10:20:50.32Z",
"expiresOn": "2022-06-09T10:20:50.32Z"
"issuedOn": "2022-06-08T10:20:50.32Z",
"validity": {
"notBefore": "2022-06-08T10:20:50.32Z",
"notAfter": "2022-06-09T10:20:50.32Z"
},
"claimSpec": "Oak trusted runtime does not store or log any parts of the incoming request",
"evidence": [
Expand Down Expand Up @@ -312,14 +289,11 @@ shown in the following example.

"predicateType": "https://gh/project-oak/transparent-release/schema/claim/v1",
"predicate": {
"issuer": {
"id": "mailto:[email protected]"
},
"claimType": "https://gh/project-oak/transparent-release/schema/fuzz_report/v1",
"metadata": {
"issuedOn": "2022-06-08T10:20:50.32Z",
"validFrom": "2022-06-08T10:20:50.32Z",
"expiresOn": "2022-06-09T10:20:50.32Z"
"issuedOn": "2022-06-08T10:20:50.32Z",
"validity": {
"notBefore": "2022-06-08T10:20:50.32Z",
"notAfter": "2022-06-09T10:20:50.32Z"
},
"claimSpec": {
"fuzz_target": {
Expand Down
58 changes: 25 additions & 33 deletions pkg/amber/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,28 @@ const AmberClaimV1 = "https://github.com/project-oak/transparent-release/claim/v

// ClaimPredicate gives the claim predicate definition.
type ClaimPredicate struct {
// The issuer of the claim.
Issuer ClaimIssuer `json:"issuer"`
// URI indicating the type of the claim. It determines the meaning of
// `ClaimSpec` and `Evidence`.
ClaimType string `json:"claimType"`
// An optional arbitrary object that gives a detailed description of the claim.
ClaimSpec interface{} `json:"claimSpec,omitempty"`
// Metadata about this claim.
Metadata *ClaimMetadata `json:"metadata,omitempty"`
// IssuedOn specifies the timestamp (encoded as an Epoch time) when the
// claim was issued.
IssuedOn *time.Time `json:"issuedOn"`
// Validity duration of this claim.
Validity *ClaimValidity `json:"validity"`
// A collection of artifacts that support the truth of the claim.
Evidence []ClaimEvidence `json:"evidence,omitempty"`
}

// ClaimIssuer identifies the entity that issued the claim.
type ClaimIssuer struct {
// URI indicating the issuer's identity. Could be an email address with
// mailto as the scheme (e.g., mailto:[email protected]).
ID string `json:"id"`
}

// ClaimMetadata contains metadata about the issued claims.
type ClaimMetadata struct {
// IssuedOn specifies the timestamp (encoded as the Epoch time) when the
// claim was issued.
IssuedOn *time.Time `json:"issuedOn"`
// ExpiresOn is an optional field specifying an expiry timestamp (also
// encoded as the Epoch time) for the claim.
ExpiresOn *time.Time `json:"expiresOn,omitempty"`
// ClaimValidity contains validity time range of an issued claim.
type ClaimValidity struct {
// NotBefore specifies the timestamp (encoded as an Epoch time) from which
// the claim is effective, and the subject artifact is endorsed for use.
NotBefore *time.Time `json:"notBefore"`
// NotAfter specifies the timestamp (encoded as an Epoch time) from which
// the artifact is no longer endorsed for use.
NotAfter *time.Time `json:"notAfter"`
}

// ClaimEvidence provides a list of artifacts that serve as the evidence for
Expand Down Expand Up @@ -102,12 +96,6 @@ func ValidateAmberClaim(statement intoto.Statement) (*ClaimPredicate, error) {

// validateClaimPredicate validates details about the ClaimPredicate.
func validateClaimPredicate(predicate ClaimPredicate) (*ClaimPredicate, error) {
// Verify that the issuer ID is a valid URI
parsedURI, err := url.Parse(predicate.Issuer.ID)
if err != nil || parsedURI.Scheme == "" {
return nil, fmt.Errorf("the Issuer ID (%s) is not a valid URI", predicate.Issuer.ID)
}

// Verify URIs of all evidence are valid.
for _, evidence := range predicate.Evidence[:] {
parsedURI, err := url.Parse(evidence.URI)
Expand All @@ -116,14 +104,18 @@ func validateClaimPredicate(predicate ClaimPredicate) (*ClaimPredicate, error) {
}
}

// Verify that ExpiresOn is greater than IssuedOn, if the former is provided.
if predicate.Metadata != nil {
if predicate.Metadata.ExpiresOn != nil &&
predicate.Metadata.ExpiresOn.Before(*predicate.Metadata.IssuedOn) {
return nil, fmt.Errorf("expiredOn (%v) is before issuedOn (%v)",
*predicate.Metadata.ExpiresOn,
*predicate.Metadata.IssuedOn)
}
// Verify that NotBefore is after than IssuedOn (inclusive).
if predicate.Validity.NotBefore.Before(*predicate.IssuedOn) {
return nil, fmt.Errorf("notBefore (%v) is before issuedOn (%v)",
*predicate.Validity.NotBefore,
*predicate.IssuedOn)
}

// Verify that NotAfter is after than NotBefore (exclusive).
if !predicate.Validity.NotAfter.After(*predicate.Validity.NotBefore) {
return nil, fmt.Errorf("notAfter (%v) is not after notBefore (%v)",
*predicate.Validity.NotAfter,
*predicate.Validity.NotBefore)
}

return &predicate, nil
Expand Down
53 changes: 51 additions & 2 deletions pkg/amber/endorsement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package amber

import (
"encoding/json"
"log"
"testing"
"time"
)
Expand All @@ -37,11 +39,58 @@ func TestExampleAmberEndorsement(t *testing.T) {
}

want := time.Date(2022, 7, 8, 10, 20, 50, 32, time.UTC)
if claimPredicate.Metadata.IssuedOn.Equal(want) {
t.Errorf("Unexpected IssuedOn: got %v, want %v", claimPredicate.Metadata.IssuedOn, want)
if claimPredicate.IssuedOn.Equal(want) {
t.Errorf("Unexpected IssuedOn: got %v, want %v", claimPredicate.IssuedOn, want)
}

if len(claimPredicate.Evidence) != 1 {
t.Errorf("Exactly one evidence is expected: got %d", len(claimPredicate.Evidence))
}
}

func TestIssuedAfterNotBeforeEndorsement(t *testing.T) {
// Use the same example above, but set the NotBefore timestamp to two days earlier.
bytes := tweakValidity(t, -2, 0)

// Expect an error, since now the NotBefore is before the IssuedOn timestamp.
if _, err := ParseEndorsementV2Bytes(bytes); err == nil {
t.Fatalf("Expected an error about invalid NotBefore timestamp")
}
}

func TestNotAfterBeforeNotBeforeEndorsement(t *testing.T) {
// Use the same example above, but set the NotAfter timestamp to 31 days earlier.
bytes := tweakValidity(t, 0, -31)

// Expect an error, since now the NotBefore is the same as the NotAfter timestamp.
if _, err := ParseEndorsementV2Bytes(bytes); err == nil {
t.Fatalf("Expected an error about invalid validity")
}
}

// Helper function for creating new test cases from the hard-coded one.
func tweakValidity(t *testing.T, daysAddedToNotBefore, daysAddedToNotAfter int) []byte {
examplePath := "../../schema/amber-claim/v1/example.json"

endorsement, err := ParseEndorsementV2File(examplePath)
if err != nil {
t.Fatalf("Failed to parse the example endorsement file: %v", err)
}

claimPredicate := endorsement.Predicate.(ClaimPredicate)
newNotBefore := claimPredicate.Validity.NotBefore.AddDate(0, 0, daysAddedToNotBefore)
newNotAfter := claimPredicate.Validity.NotAfter.AddDate(0, 0, daysAddedToNotAfter)

claimPredicate.Validity = &ClaimValidity{
NotBefore: &newNotBefore,
NotAfter: &newNotAfter,
}
endorsement.Predicate = claimPredicate

bytes, err := json.Marshal(endorsement)
if err != nil {
log.Fatalf("Couldn't marshal the provenance: %v", err)
}

return bytes
}
7 changes: 4 additions & 3 deletions schema/amber-claim/v1/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
"id": "mailto:[email protected]"
},
"claimType": "https://github.com/project-oak/transparent-release/endorsement/v2",
"metadata": {
"issuedOn": "2022-07-08T10:20:50.32Z",
"expiresOn": "2022-08-08T10:20:50.32Z"
"issuedOn": "2022-07-08T10:20:50.32Z",
"validity": {
"notBefore": "2022-07-08T10:20:50.32Z",
"notAfter": "2022-08-08T10:20:50.32Z"
},
"evidence": [
{
Expand Down

0 comments on commit 878e8e1

Please sign in to comment.