# Verifying an Artifact with a Witness Policy

<span class="tip-text">💡 Tip: If this is your first time using Witness, you might benefit from trying the <a href="./getting-started.md">Getting Started</a> tutorial first!</span>

## Intro
This quick tutorial will walk you through a simple example of how Witness can be used. To complete it
successfully, you will need the following:

- [jq](https://jqlang.github.io/jq/)
- [yq](https://kislyuk.github.io/yq/)
- [openssl](https://www.openssl.org/)
- [wget](https://www.gnu.org/software/wget/)
- [base64](https://www.gnu.org/software/coreutils/manual/html_node/base64-invocation.html) (which is part of GNU coreutils)

You will also of course need to have witness installed, which can be achieved by following the [Quick Start](/README.md#quick-start).

## Let's Go!

### Generating a Key Pair
The first step is to generate a key pair that will be used to sign the attestations. This can be done with the following `openssl` command:

`openssl genrsa -out buildkey.pem 2048`

Next, we will extract the public key from the key pair:

`openssl rsa -in buildkey.pem -outform PEM -pubout -out buildpublic.pem`

### Generating the Attestations
Now that we have created the key pairs, we can use them creating and signing an attestation by running the following command:

*Important Note: Witness generates the product attestation based on new files in the working directory. Make sure `./hello.txt` does NOT exist when running this command.*

```
witness run -s build -a environment -k buildkey.pem -o build-attestation.json -- \
bash -c "echo 'hello' > hello.txt"
```

In this command you will notice a few flags:

- `-s build` specifies the step name. This is helpful for identifying which step of the supply chain these particular attestations are from.
- `-a environment` specifies the attestor to use. There are a [wide variety of attestors](/docs/concepts/attestor.md) available which can called in a list using this flag.
- `-k buildkey.pem` specifies the private key we generated to use for signing the attestations.
- `-o build-attestation.json` specifies the output file for the attestations to be written to in `json` format.

Upon running this command (and it exiting successfully), you should see a file named `build-attestation.json` in your current working directory. This file contains the attestations that were generated by the command.

### Viewing the Attestation
If you view the `build-attestation.json` file, you might be disappointed to find a load of jibberish. Do not fear, it is meant to be this way! The attestation is base64 encoded and stored in a [DSSE Envelope](https://github.com/secure-systems-lab/dsse), which
is a simple, foolproof way of signing arbitrary data.

To view the contents of the attestation, you can use the following command:

`cat build-attestation.json | jq -r .payload | base64 -d | jq .`

This will print the contents of the attestation in a human-readable format. The output should look something like:

```
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "subject": [
    {
      "name": "https://witness.dev/attestations/product/v0.1/file:hello.txt",
      "digest": {
        "gitoid:sha1": "gitoid:blob:sha1:ce013625030ba8dba906f756967f9e9ca394464a",
        "gitoid:sha256": "gitoid:blob:sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813",
        "sha256": "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03"
      }
    }
  ],
  "predicateType": "https://witness.testifysec.com/attestation-collection/v0.1",
  "predicate": {
    "name": "build",
    "attestations": [
      {
        "type": "https://witness.dev/attestations/environment/v0.1",
        "attestation": {
          "os": "darwin",
...
```

This is all well and good, but attestations hardly make for good bedtime reading (😴), so let's see if we can define a policy so we can automate the verification process .

### Specifying the Rego Constraints
One of the key features of Witness is its ability to enforce policies using the [Open Policy Agent (OPA) Rego language](https://www.openpolicyagent.org/docs/latest/policy-language/). This allows us to specify rules that must be followed when generating attestations, and ensures that the artifacts produced by the pipeline meet the requirements specified in the policy.

To create the Rego policy, we first need to define the rules that we want to enforce. For example, if we want to ensure that the `./hello.txt` file is created with the correct contents we could use the following Rego policy:

```
cat <<EOF >> cmd.rego
package commandrun

deny[msg] {
    input.exitcode != 0
    msg := "exitcode not 0"
}

deny[msg] {
    input.cmd[2] != "echo 'hello' > hello.txt"
    msg := "cmd not correct"
}
EOF
```

You can save this to a file locally by copying the above code, pasting it into your terminal and pressing `enter`. This will create a file named `cmd.rego` in your current working directory.

#### But what does it mean?

This policy specifies two rules:

1. The policy must 'deny' if the exit code of the command is not 0:
```
deny[msg] {
    input.exitcode != 0
    msg := "exitcode not 0"
}
```

2. The policy must 'deny' if the command for creating `./hello.txt` is not what we expect:
```

deny[msg] {
    input.cmd[2] != "echo 'hello' > hello.txt"
    msg := "cmd not correct"
}
```

What's brilliant about Rego is that these are just examples. You can define a Rego policy that inspects any attribute within the attestation.

For example, we could create a policy that checks the user that ran the command:
```
package environment
deny[msg] {

    input.username != "witty" 
    msg := "username not correct"
}
```

Or the current working directory:
```
package environment
deny[msg] {

    input.variables.PWD != "/home/witty/secret-lab"
    msg := "working directory not correct"
}
```
This allows you to create highly customizable and granular policies to ensure the integrity and security of your build process.

### Creating the Witness Policy
Next, we need to place our Rego policy into a Witness Policy. While Rego is going to help us verify the attestation contents, the Witness Policy is going to take care of verifying the presence of each expected attestation, as well as
 the signature attached to it.

Here is an example policy template:
```
cat <<EOF >> policy-template.yaml
expires: "2035-12-17T23:57:40-05:00"
steps:
  build:
      name: build
      attestations:
        - type: https://witness.dev/attestations/material/v0.1
        - type: https://witness.dev/attestations/product/v0.1
        - type: https://witness.dev/attestations/command-run/v0.1
          regoPolicies:
          - name:  "exitcode"
            module: "{{CMD_MODULE}}"
      functionaries:
        - type: publickey
          publickeyid: "{{KEYID}}"
publickeys:
  "{{KEYID}}":
    keyid: "{{KEYID}}"
    key:
EOF
```

You can save this to a file locally by copying the above code, pasting it into your terminal and pressing `enter`. This will create a file named `policy-template.yaml` in your current working directory.

#### But what does it mean?
In this Witness Policy, we have defined a single step (you can define more than one) that we expect the supply chain of any artifact verified by it should have gone through:
```
steps:
  build:
      name: build
```

For this step, we expect to find an [Attestation Collection](/docs/concepts/attestor.md) that contains three types of attestation: material, product and command-run:
```
  attestations:
    - type: https://witness.dev/attestations/material/v0.1
    - type: https://witness.dev/attestations/product/v0.1
    - type: https://witness.dev/attestations/command-run/v0.1
```

For the `command-run` attestation, we will also be using the Rego policy we defined earlier:

```
  - type: https://witness.dev/attestations/command-run/v0.1
    regoPolicies:
    - name:  "exitcode"
      module: "{{CMD_MODULE}}"
```

Finally, we will be using our public key ID (the sha256sum of our public key) to verify the signature of the attestations. This public key is our digital identity, and in this case we are the functionary and we are expected to have signed the attestations for the build step:
```
  functionaries:
    - type: publickey
      publickeyid: "{{KEYID}}"
```

The key IDs are mapped to the base64 encodings of the public keys in the `publickeys` section:
```
  publickeys:
    "{{KEYID}}":
      keyid: "{{KEYID}}"
      key:
```

It is important to note that the policy template can be used to define multiple steps in an artifacts supply chain, and each step can have its own set of attestations and rules. This allows us to create complex and granular policies that ensure the integrity of the supply chain from start to finish.

### Templating the Policy
Before we can use the policy, we need to populate it with the base64 encoded public key, the key ID, and the Rego policy (which also needs to be base64 encoded):

*Note: This script uses the `shasum` tool on MacOS and `sha256sum` on Linux. If you are using a different operating system, you may need to modify the script to use the appropriate tool. Contributions to make this script more portable are welcome!*
```bash
cat << 'EOF' > template-policy.sh

# Requires yq v4.2.0
cmd_b64="$(openssl base64 -A <"cmd.rego")"
pubkey_b64="$(openssl base64 -A <"buildpublic.pem")"
cp policy-template.yaml policy.tmp.yaml

# Calculate SHA256 hash (macOS and Linux compatible)
if [[ "$(uname)" == "Darwin" ]]; then

    keyid=$(shasum -a 256 buildpublic.pem | awk '{print $1}')
    sed -i '' "s/{{KEYID}}/$keyid/g" policy.tmp.yaml
    sed -i '' "s/{{CMD_MODULE}}/$cmd_b64/g" policy.tmp.yaml

	
else
    keyid=$(sha256sum buildpublic.pem | awk '{print $1}')
    sed -i "s/{{KEYID}}/$keyid/g" policy.tmp.yaml
    sed -i "s/{{CMD_MODULE}}/$cmd_b64/g" policy.tmp.yaml


fi
yq eval ".publickeys.\"${keyid}\".key = \"${pubkey_b64}\"" --inplace policy.tmp.yaml

# Use `-o=json` instead of deprecated `--tojson`
yq eval -o=json policy.tmp.yaml > policy.json

# Clean up the temporary file
rm policy.tmp.yaml
EOF
chmod +x template-policy.sh
```

Once again, you can save this to a file locally by copying the above code, pasting it into your terminal and pressing `enter`. This will create a file named `template-policy.sh` in your current working directory, but also make it executable (with `chmod +x`).

Now you can go ahead and run the script, which will output a final `policy.json` file.

### Signing the Witness Policy

Signing the policy is an important step in the attestation process, as it ensures the authenticity and integrity of the policy. This is essential for ensuring the security of the build process and preventing tampering of build materials and artifacts.

In order to sign the policy, we need to use a key pair that is trusted by the verification process. Once again, we can generate this pair with `openssl`:
```
openssl genrsa -out policykey.pem 2048
openssl rsa -in policykey.pem -outform PEM -pubout -out policypublic.pem
```

Once the key pair has been generated, we can use the private key to sign the policy using the Witness sign command as follows:
```
witness sign -k policykey.pem -f policy.json -o policy.signed.json
```

The above command only has three flags:

- `-k policykey.pem` specifies the private key that will be used to sign the policy.
- `-f policy.json` specifies the policy file that will be signed.
- `-o policy.signed.json` specifies the output file for the signed policy.

The signed policy file can now be used to verify the attestations we generated earlier. This ensures that the policy has not been tampered with and that it can be trusted during the verification process.

Okay, I hear ya, I hear ya, let's verify some attestations already!

### Verifying the Attestations
Once the policy has been signed and the attestations have been generated, we can use the witness verify command to verify that the attestations meet the requirements specified in the policy. This is done by running the witness verify command with the following arguments:

```
witness verify -k policypublic.pem -p policy.signed.json -a build-attestation.json -f hello.txt
```

- `-k policypublic.pem` specifies the public key that was used to sign the policy.
- `-p policy.signed.json` specifies the signed policy file.
- `-a build-attestation.json` specifies the attestation file that we generated earlier.
- `-f hello.txt` specifies the artifact that was produced by the pipeline.


### You did it! 🎉
If the attestations meet the requirements specified in the policy, the witness verify command will output a message indicating that the verification succeeded along with references to the evidence. If the attestations do not meet the requirements, the witness verify command will output an error message indicating which requirement was not met.

## What's Next?
If you enjoyed this tutorial, you might enjoy learning about how Witness can be used to sign attestations without any keys! Sound intriguing? [Let's go!](./sigstore-keyless.md)


## Did You Know?
One of the key benefits of using Witness is that it is not only a standalone tool, but also a library that can be embedded into other applications such as admission controllers and runtime visibility tooling. Be sure to check out go-witness [here](https://github.com/in-toto/go-witness).
