From 6ba639e12696a50e4e21c64e7c0b04a2436a670a Mon Sep 17 00:00:00 2001 From: Dariksha Date: Fri, 17 May 2024 11:39:09 +0530 Subject: [PATCH 1/6] Changed deprecated keys and used cryptosigner Signed-off-by: Dariksha --- README.md | 14 +++++++------- owner_alice/create_layout.py | 20 ++++++++++++++------ requirements.txt | 1 + run_demo.py | 14 +++++++------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 2b58de9..d689744 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ directory and perform the step. ```shell cd ../functionary_bob -in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --key bob -- git clone https://github.com/in-toto/demo-project.git +in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --signing-key bob -- git clone https://github.com/in-toto/demo-project.git ``` Here is what happens behind the scenes: @@ -124,7 +124,7 @@ So first Bob records the state of the files he will modify: ```shell # In functionary_bob directory -in-toto-record start --step-name update-version --use-dsse --key bob --materials demo-project/foo.py +in-toto-record start --step-name update-version --use-dsse --signing-key bob --materials demo-project/foo.py ``` Then Bob uses an editor of his choice to update the version number in `demo-project/foo.py`, e.g.: @@ -137,7 +137,7 @@ And finally he records the state of files after the modification and produces a link metadata file called `update-version.[Bob's keyid].link`. ```shell # In functionary_bob directory -in-toto-record stop --step-name update-version --use-dsse --key bob --products demo-project/foo.py +in-toto-record stop --step-name update-version --use-dsse --signing-key bob --products demo-project/foo.py ``` Bob has done his work and can send over the sources to Carl, who will create @@ -154,7 +154,7 @@ to change to Carl's directory and create a package of the software project ```shell cd ../functionary_carl -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project ``` This will create another step link metadata file, called `package.[Carl's keyid].link`. @@ -175,7 +175,7 @@ cd final_product # Fetch Alice's public key from a trusted source to verify the layout signature # Note: The functionary public keys are fetched from the layout cp ../owner_alice/alice.pub . -in-toto-verify --layout root.layout --layout-key alice.pub +in-toto-verify --layout root.layout --verification-keys alice.pub ``` This command will verify that 1. the layout has not expired, @@ -208,7 +208,7 @@ Carl thought that this is the genuine code he got from Bob and unwittingly packages the tampered version of foo.py ```shell -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project ``` and ships everything out as final product to the client: ```shell @@ -220,7 +220,7 @@ cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/u ```shell cd final_product -in-toto-verify --layout root.layout --layout-key alice.pub +in-toto-verify --layout root.layout --verification-keys alice.pub ``` This time, in-toto will detect that the product `foo.py` from Bob's `update-version` step was not used as material in Carl's `package` step (the verified hashes diff --git a/owner_alice/create_layout.py b/owner_alice/create_layout.py index 1f14c54..8cf8186 100644 --- a/owner_alice/create_layout.py +++ b/owner_alice/create_layout.py @@ -1,16 +1,24 @@ -from securesystemslib import interface -from securesystemslib.signer import SSlibSigner +from cryptography.hazmat.primitives.serialization import load_pem_private_key +from cryptography.hazmat.primitives.serialization import load_pem_public_key +from securesystemslib.signer import CryptoSigner from in_toto.models.layout import Layout from in_toto.models.metadata import Envelope def main(): # Load Alice's private key to later sign the layout - key_alice = interface.import_rsa_privatekey_from_file("alice") - signer_alice = SSlibSigner(key_alice) + with open("alice", "rb") as f: + key_alice = load_pem_private_key(f.read(), None) + + signer_alice = CryptoSigner(key_alice) # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout - key_bob = interface.import_rsa_publickey_from_file("../functionary_bob/bob.pub") - key_carl = interface.import_rsa_publickey_from_file("../functionary_carl/carl.pub") + # https://github.com/in-toto/in-toto/issues/663 + with open("../functionary_bob/bob.pub", "rb") as f: + key_bob = load_pem_public_key(f.read(), None) + + with open("../functionary_carl/carl.pub", "rb") as f: + key_carl = load_pem_public_key(f.read(), None) + layout = Layout.read({ "_type": "layout", diff --git a/requirements.txt b/requirements.txt index a6ee547..54171f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ in-toto==2.3.0 +cryptography==42.0.7 diff --git a/run_demo.py b/run_demo.py index 8c5c32e..e81aca0 100644 --- a/run_demo.py +++ b/run_demo.py @@ -33,7 +33,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name clone --products demo-project/foo.py" - " --key bob -- git clone https://github.com/in-toto/demo-project.git") + " --signing-key bob -- git clone https://github.com/in-toto/demo-project.git") print(clone_cmd) subprocess.call(shlex.split(clone_cmd)) @@ -43,7 +43,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --key bob" + " --signing-key bob" " --materials demo-project/foo.py") print(update_version_start_cmd) @@ -58,7 +58,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --key bob" + " --signing-key bob" " --products demo-project/foo.py") print(update_version_stop_cmd) @@ -73,7 +73,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --key carl --record-streams" + " --signing-key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -94,7 +94,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --layout-key alice.pub") + " --verification-keys alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) print("Return value: " + str(retval)) @@ -115,7 +115,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --key carl --record-streams" + " --signing-key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -136,7 +136,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --layout-key alice.pub") + " --verification-keys alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) From 5b9643b4c4f9e59fb78c23dcdaf14d88a77c4afa Mon Sep 17 00:00:00 2001 From: Dariksha Date: Fri, 17 May 2024 14:16:01 +0530 Subject: [PATCH 2/6] Added some changes in create_layout.py Signed-off-by: Dariksha --- owner_alice/create_layout.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/owner_alice/create_layout.py b/owner_alice/create_layout.py index 8cf8186..24fe8f0 100644 --- a/owner_alice/create_layout.py +++ b/owner_alice/create_layout.py @@ -3,6 +3,24 @@ from securesystemslib.signer import CryptoSigner from in_toto.models.layout import Layout from in_toto.models.metadata import Envelope +from securesystemslib.signer import SSlibKey +from typing import Dict, Any + +def _load_public_key_from_file(path: str) -> Dict[str, Any]: + """Internal helper to load key from SubjectPublicKeyInfo/PEM file.""" + with open(path, "rb") as f: + data = f.read() + + crypto_public_key = load_pem_public_key(data) + key = SSlibKey.from_crypto(crypto_public_key) + + # Create a key_dict, which is accepted by `verifylib.in_toto_verify` or `Metablock.verify_signature` + # NOTE: securesystemslib and in-toto key dicts differ: + # the former don't include the keyid, which the latter require + key_dict = key.to_dict() + key_dict["keyid"] = key.keyid + + return key_dict def main(): # Load Alice's private key to later sign the layout @@ -13,11 +31,8 @@ def main(): # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout # https://github.com/in-toto/in-toto/issues/663 - with open("../functionary_bob/bob.pub", "rb") as f: - key_bob = load_pem_public_key(f.read(), None) - - with open("../functionary_carl/carl.pub", "rb") as f: - key_carl = load_pem_public_key(f.read(), None) + key_bob = _load_public_key_from_file("../functionary_bob/bob.pub") + key_carl = _load_public_key_from_file("../functionary_carl/carl.pub") layout = Layout.read({ From 5e82bd5b3882e8dd0ec3365bb1725ba2161c9638 Mon Sep 17 00:00:00 2001 From: Dariksha Date: Fri, 17 May 2024 14:49:53 +0530 Subject: [PATCH 3/6] Discarded changes from README.md and run_demo.py Signed-off-by: Dariksha --- README.md | 16 ++++++++-------- run_demo.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d689744..b2694ad 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ directory and perform the step. ```shell cd ../functionary_bob -in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --signing-key bob -- git clone https://github.com/in-toto/demo-project.git +in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --key bob -- git clone https://github.com/in-toto/demo-project.git ``` Here is what happens behind the scenes: @@ -124,7 +124,7 @@ So first Bob records the state of the files he will modify: ```shell # In functionary_bob directory -in-toto-record start --step-name update-version --use-dsse --signing-key bob --materials demo-project/foo.py +in-toto-record start --step-name update-version --use-dsse --key bob --materials demo-project/foo.py ``` Then Bob uses an editor of his choice to update the version number in `demo-project/foo.py`, e.g.: @@ -137,7 +137,7 @@ And finally he records the state of files after the modification and produces a link metadata file called `update-version.[Bob's keyid].link`. ```shell # In functionary_bob directory -in-toto-record stop --step-name update-version --use-dsse --signing-key bob --products demo-project/foo.py +in-toto-record stop --step-name update-version --use-dsse --key bob --products demo-project/foo.py ``` Bob has done his work and can send over the sources to Carl, who will create @@ -154,7 +154,7 @@ to change to Carl's directory and create a package of the software project ```shell cd ../functionary_carl -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project ``` This will create another step link metadata file, called `package.[Carl's keyid].link`. @@ -175,7 +175,7 @@ cd final_product # Fetch Alice's public key from a trusted source to verify the layout signature # Note: The functionary public keys are fetched from the layout cp ../owner_alice/alice.pub . -in-toto-verify --layout root.layout --verification-keys alice.pub +in-toto-verify --layout root.layout --layout-key alice.pub ``` This command will verify that 1. the layout has not expired, @@ -208,7 +208,7 @@ Carl thought that this is the genuine code he got from Bob and unwittingly packages the tampered version of foo.py ```shell -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project ``` and ships everything out as final product to the client: ```shell @@ -220,7 +220,7 @@ cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/u ```shell cd final_product -in-toto-verify --layout root.layout --verification-keys alice.pub +in-toto-verify --layout root.layout --layout-key alice.pub ``` This time, in-toto will detect that the product `foo.py` from Bob's `update-version` step was not used as material in Carl's `package` step (the verified hashes @@ -253,4 +253,4 @@ The same script can be used to sequentially execute all commands listed above. J ```bash # In the demo directory python run_demo.py -``` +``` \ No newline at end of file diff --git a/run_demo.py b/run_demo.py index e81aca0..6cd4c95 100644 --- a/run_demo.py +++ b/run_demo.py @@ -33,7 +33,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name clone --products demo-project/foo.py" - " --signing-key bob -- git clone https://github.com/in-toto/demo-project.git") + " --key bob -- git clone https://github.com/in-toto/demo-project.git") print(clone_cmd) subprocess.call(shlex.split(clone_cmd)) @@ -43,7 +43,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --signing-key bob" + " --key bob" " --materials demo-project/foo.py") print(update_version_start_cmd) @@ -58,7 +58,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --signing-key bob" + " --key bob" " --products demo-project/foo.py") print(update_version_stop_cmd) @@ -73,7 +73,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --signing-key carl --record-streams" + " --key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -94,7 +94,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --verification-keys alice.pub") + " --layout-key alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) print("Return value: " + str(retval)) @@ -115,7 +115,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --signing-key carl --record-streams" + " --key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -136,7 +136,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --verification-keys alice.pub") + " --layout-key alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) @@ -185,4 +185,4 @@ def main(): supply_chain() if __name__ == '__main__': - main() + main() \ No newline at end of file From 342f7aca581380fdbbe6a2dc95aaee5b202c23c9 Mon Sep 17 00:00:00 2001 From: Dariksha Date: Fri, 17 May 2024 15:21:23 +0530 Subject: [PATCH 4/6] Changed create_layout.py Signed-off-by: Dariksha --- owner_alice/create_layout.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/owner_alice/create_layout.py b/owner_alice/create_layout.py index 24fe8f0..d61f271 100644 --- a/owner_alice/create_layout.py +++ b/owner_alice/create_layout.py @@ -1,26 +1,8 @@ from cryptography.hazmat.primitives.serialization import load_pem_private_key -from cryptography.hazmat.primitives.serialization import load_pem_public_key from securesystemslib.signer import CryptoSigner from in_toto.models.layout import Layout from in_toto.models.metadata import Envelope -from securesystemslib.signer import SSlibKey -from typing import Dict, Any - -def _load_public_key_from_file(path: str) -> Dict[str, Any]: - """Internal helper to load key from SubjectPublicKeyInfo/PEM file.""" - with open(path, "rb") as f: - data = f.read() - - crypto_public_key = load_pem_public_key(data) - key = SSlibKey.from_crypto(crypto_public_key) - - # Create a key_dict, which is accepted by `verifylib.in_toto_verify` or `Metablock.verify_signature` - # NOTE: securesystemslib and in-toto key dicts differ: - # the former don't include the keyid, which the latter require - key_dict = key.to_dict() - key_dict["keyid"] = key.keyid - - return key_dict +from in_toto.models._signer import load_public_key_from_file def main(): # Load Alice's private key to later sign the layout @@ -31,8 +13,8 @@ def main(): # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout # https://github.com/in-toto/in-toto/issues/663 - key_bob = _load_public_key_from_file("../functionary_bob/bob.pub") - key_carl = _load_public_key_from_file("../functionary_carl/carl.pub") + key_bob = load_public_key_from_file("../functionary_bob/bob.pub") + key_carl = load_public_key_from_file("../functionary_carl/carl.pub") layout = Layout.read({ From e4bbdf9d85444fb3fb0224ba2e3709afe1f81fb0 Mon Sep 17 00:00:00 2001 From: Dariksha Date: Sat, 18 May 2024 11:35:02 +0530 Subject: [PATCH 5/6] Fixed required files Signed-off-by: Dariksha --- README.md | 159 +++++++++++++++++------------------ owner_alice/create_layout.py | 2 +- run_demo.py | 40 ++++----- run_demo_md.py | 48 +++++------ 4 files changed, 121 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index b2694ad..ede6a1b 100644 --- a/README.md +++ b/README.md @@ -14,24 +14,24 @@ as the client who verifies the final product. ## Download and setup in-toto on \*NIX (Linux, OS X, ..) -__Virtual Environments (optional)__ +_Virtual Environments (optional)_ -We highly recommend installing `in-toto` and its dependencies in a -[`venv`](https://docs.python.org/3/library/venv.html) Python virtual +We highly recommend installing in-toto and its dependencies in a +[venv](https://docs.python.org/3/library/venv.html) Python virtual environment. Just copy-paste the following snippet to create a virtual environment: -```bash +bash # Create the virtual environment python -m venv in-toto-demo # Activate the virtual environment # This will add the prefix "(in-toto-demo)" to your shell prompt source in-toto-demo/bin/activate -``` -__Get demo files and install in-toto__ -```bash + +_Get demo files and install in-toto_ +bash # Fetch the demo repo using git git clone https://github.com/in-toto/demo.git @@ -40,16 +40,16 @@ cd demo # Install a compatible version of in-toto pip install -r requirements.txt -``` + *Note: If you are having troubles installing in-toto, make sure you have all the system dependencies. See the [installation guide on in-toto.readthedocs.io](https://in-toto.readthedocs.io/en/latest/installing.html) for details.* -Inside the demo directory you will find four directories: `owner_alice`, -`functionary_bob`, `functionary_carl` and `final_product`. Alice, Bob and Carl +Inside the demo directory you will find four directories: owner_alice, +functionary_bob, functionary_carl and final_product. Alice, Bob and Carl already have RSA keys in each of their directories. This is what you see: -```bash +bash tree # If you don't have tree, try 'find .' instead # the tree command gives you the following output # . @@ -68,7 +68,7 @@ tree # If you don't have tree, try 'find .' instead # ├── requirements.txt # ├── run_demo.py # └── run_demo_md.py -``` + ## Run the demo commands Note: if you don't want to type or copy & paste commands and would rather watch @@ -82,153 +82,153 @@ the demo. In this software supply chain layout, we have Alice, who is the project owner that creates the layout, Bob, who clones the project's repo and performs some pre-packaging editing (update version number), and Carl, who uses -`tar` to package the project sources into a tarball, which +tar to package the project sources into a tarball, which together with the in-toto metadata composes the final product that will eventually be installed and verified by the end user. -```shell +shell # Create and sign the software supply chain layout on behalf of Alice cd owner_alice python create_layout.py -``` + The script will create a layout, add Bob's and Carl's public keys (fetched from -their directories), sign it with Alice's private key and dump it to `root.layout`. -In `root.layout`, you will find that (besides the signature and other information) -there are three steps, `clone`, `update-version` and `package`, that +their directories), sign it with Alice's private key and dump it to root.layout. +In root.layout, you will find that (besides the signature and other information) +there are three steps, clone, update-version and package, that the functionaries Bob and Carl, identified by their public keys, are authorized to perform. ### Clone project source code (Bob) Now, we will take the role of the functionary Bob and perform the step -`clone` on his behalf, that is we use in-toto to clone the project repo from GitHub and +clone on his behalf, that is we use in-toto to clone the project repo from GitHub and record metadata for what we do. Execute the following commands to change to Bob's directory and perform the step. -```shell +shell cd ../functionary_bob -in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --key bob -- git clone https://github.com/in-toto/demo-project.git -``` +in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --signing-key bob -- git clone https://github.com/in-toto/demo-project.git + Here is what happens behind the scenes: - 1. In-toto wraps the command `git clone https://github.com/in-toto/demo-project.git`, - 1. hashes the contents of the source code, i.e. `demo-project/foo.py`, + 1. In-toto wraps the command git clone https://github.com/in-toto/demo-project.git, + 1. hashes the contents of the source code, i.e. demo-project/foo.py, 1. adds the hash together with other information to a metadata file, 1. signs the metadata with Bob's private key, and - 1. stores everything to `clone.[Bob's keyid].link`. + 1. stores everything to clone.[Bob's keyid].link. ### Update version number (Bob) Before Carl packages the source code, Bob will update -a version number hard-coded into `foo.py`. He does this using the `in-toto-record` command, +a version number hard-coded into foo.py. He does this using the in-toto-record command, which produces the same link metadata file as above but does not require Bob to wrap his action in a single command. So first Bob records the state of the files he will modify: -```shell +shell # In functionary_bob directory -in-toto-record start --step-name update-version --use-dsse --key bob --materials demo-project/foo.py -``` +in-toto-record start --step-name update-version --use-dsse --signing-key bob --materials demo-project/foo.py -Then Bob uses an editor of his choice to update the version number in `demo-project/foo.py`, e.g.: -```shell +Then Bob uses an editor of his choice to update the version number in demo-project/foo.py, e.g.: + +shell sed -i.bak 's/v0/v1/' demo-project/foo.py && rm demo-project/foo.py.bak -``` + And finally he records the state of files after the modification and produces -a link metadata file called `update-version.[Bob's keyid].link`. -```shell +a link metadata file called update-version.[Bob's keyid].link. +shell # In functionary_bob directory -in-toto-record stop --step-name update-version --use-dsse --key bob --products demo-project/foo.py -``` +in-toto-record stop --step-name update-version --use-dsse --signing-key bob --products demo-project/foo.py + Bob has done his work and can send over the sources to Carl, who will create the package for the user. -```shell +shell # Bob has to send the update sources to Carl so that he can package them cp -r demo-project ../functionary_carl/ -``` + ### Package (Carl) -Now, we will perform Carl’s `package` step by executing the following commands +Now, we will perform Carl’s package step by executing the following commands to change to Carl's directory and create a package of the software project -```shell +shell cd ../functionary_carl -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project -``` +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project + -This will create another step link metadata file, called `package.[Carl's keyid].link`. +This will create another step link metadata file, called package.[Carl's keyid].link. It's time to release our software now. ### Verify final product (client) -Let's first copy all relevant files into the `final_product` that is -our software package `demo-project.tar.gz` and the related metadata files `root.layout`, -`clone.[Bob's keyid].link`, `update-version.[Bob's keyid].link` and `package.[Carl's keyid].link`: -```shell +Let's first copy all relevant files into the final_product that is +our software package demo-project.tar.gz and the related metadata files root.layout, +clone.[Bob's keyid].link, update-version.[Bob's keyid].link and package.[Carl's keyid].link: +shell cd .. -cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/update-version.776a00e2.link functionary_carl/package.2f89b927.link functionary_carl/demo-project.tar.gz final_product/ -``` +cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ + And now run verification on behalf of the client: -```shell +shell cd final_product # Fetch Alice's public key from a trusted source to verify the layout signature # Note: The functionary public keys are fetched from the layout cp ../owner_alice/alice.pub . -in-toto-verify --layout root.layout --layout-key alice.pub -``` +in-toto-verify --layout root.layout --verification-keys alice.pub + This command will verify that 1. the layout has not expired, 2. was signed with Alice’s private key,
and that according to the definitions in the layout 3. each step was performed and signed by the authorized functionary 4. the recorded materials and products follow the artifact rules and - 5. the inspection `untar` finds what it expects. + 5. the inspection untar finds what it expects. -From it, you will see the meaningful output `PASSING` and a return value -of `0`, that indicates verification worked out well: -```shell +From it, you will see the meaningful output PASSING and a return value +of 0, that indicates verification worked out well: +shell echo $? # should output 0 -``` + ### Tampering with the software supply chain Now, let’s try to tamper with the software supply chain. Imagine that someone got a hold of the source code before Carl could package it. -We will simulate this by changing `demo-project/foo.py` on Carl's machine -(in `functionary_carl` directory) and then let Carl package and ship the +We will simulate this by changing demo-project/foo.py on Carl's machine +(in functionary_carl directory) and then let Carl package and ship the malicious code. -```shell +shell cd ../functionary_carl echo something evil >> demo-project/foo.py -``` + Carl thought that this is the genuine code he got from Bob and unwittingly packages the tampered version of foo.py -```shell -in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project -``` +shell +in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project + and ships everything out as final product to the client: -```shell +shell cd .. -cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/update-version.776a00e2.link functionary_carl/package.2f89b927.link functionary_carl/demo-project.tar.gz final_product/ -``` +cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ + ### Verifying the malicious product -```shell +shell cd final_product -in-toto-verify --layout root.layout --layout-key alice.pub -``` -This time, in-toto will detect that the product `foo.py` from Bob's `update-version` -step was not used as material in Carl's `package` step (the verified hashes +in-toto-verify --layout root.layout --verification-keys alice.pub + +This time, in-toto will detect that the product foo.py from Bob's update-version +step was not used as material in Carl's package step (the verified hashes won't match) and therefore will fail verification an return a non-zero value: -```shell +shell echo $? # should output 1 -``` + ### Wrapping up @@ -242,15 +242,14 @@ and how to use it on [in-toto's Github page](https://in-toto.github.io/). ### Clean slate If you want to run the demo again, you can use the following script to remove all the files you created above. -```bash +bash cd .. # You have to be the demo directory python run_demo.py -c -``` + ### Tired of copy-pasting commands? -The same script can be used to sequentially execute all commands listed above. Just change into the `demo` directory, run `python run_demo.py` without flags and observe the output. +The same script can be used to sequentially execute all commands listed above. Just change into the demo directory, run python run_demo.py without flags and observe the output. -```bash +bash # In the demo directory -python run_demo.py -``` \ No newline at end of file +python run_demo.py diff --git a/owner_alice/create_layout.py b/owner_alice/create_layout.py index d61f271..630aace 100644 --- a/owner_alice/create_layout.py +++ b/owner_alice/create_layout.py @@ -2,6 +2,7 @@ from securesystemslib.signer import CryptoSigner from in_toto.models.layout import Layout from in_toto.models.metadata import Envelope +# https://github.com/in-toto/in-toto/issues/663 from in_toto.models._signer import load_public_key_from_file def main(): @@ -12,7 +13,6 @@ def main(): signer_alice = CryptoSigner(key_alice) # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout - # https://github.com/in-toto/in-toto/issues/663 key_bob = load_public_key_from_file("../functionary_bob/bob.pub") key_carl = load_public_key_from_file("../functionary_carl/carl.pub") diff --git a/run_demo.py b/run_demo.py index 6cd4c95..a370b20 100644 --- a/run_demo.py +++ b/run_demo.py @@ -33,7 +33,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name clone --products demo-project/foo.py" - " --key bob -- git clone https://github.com/in-toto/demo-project.git") + " --signing-key bob -- git clone https://github.com/in-toto/demo-project.git") print(clone_cmd) subprocess.call(shlex.split(clone_cmd)) @@ -43,7 +43,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --key bob" + " --signing-key bob" " --materials demo-project/foo.py") print(update_version_start_cmd) @@ -58,7 +58,7 @@ def supply_chain(): " --verbose" " --use-dsse" " --step-name update-version" - " --key bob" + " --signing-key bob" " --products demo-project/foo.py") print(update_version_stop_cmd) @@ -73,7 +73,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --key carl --record-streams" + " --signing-key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -82,9 +82,9 @@ def supply_chain(): prompt_key("Create final product") os.chdir("..") copyfile("owner_alice/root.layout", "final_product/root.layout") - copyfile("functionary_bob/clone.776a00e2.link", "final_product/clone.776a00e2.link") - copyfile("functionary_bob/update-version.776a00e2.link", "final_product/update-version.776a00e2.link") - copyfile("functionary_carl/package.2f89b927.link", "final_product/package.2f89b927.link") + copyfile("functionary_bob/clone.210dcc50.link", "final_product/clone.210dcc50.link") + copyfile("functionary_bob/update-version.210dcc50.link", "final_product/update-version.210dcc50.link") + copyfile("functionary_carl/package.be06db20.link", "final_product/package.be06db20.link") copyfile("functionary_carl/demo-project.tar.gz", "final_product/demo-project.tar.gz") @@ -94,7 +94,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --layout-key alice.pub") + " --verification-keys alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) print("Return value: " + str(retval)) @@ -115,7 +115,7 @@ def supply_chain(): " --use-dsse" " --step-name package --materials demo-project/foo.py" " --products demo-project.tar.gz" - " --key carl --record-streams" + " --signing-key carl --record-streams" " -- tar --exclude '.git' -zcvf demo-project.tar.gz demo-project") print(package_cmd) subprocess.call(shlex.split(package_cmd)) @@ -124,9 +124,9 @@ def supply_chain(): prompt_key("Create final product") os.chdir("..") copyfile("owner_alice/root.layout", "final_product/root.layout") - copyfile("functionary_bob/clone.776a00e2.link", "final_product/clone.776a00e2.link") - copyfile("functionary_bob/update-version.776a00e2.link", "final_product/update-version.776a00e2.link") - copyfile("functionary_carl/package.2f89b927.link", "final_product/package.2f89b927.link") + copyfile("functionary_bob/clone.210dcc50.link", "final_product/clone.210dcc50.link") + copyfile("functionary_bob/update-version.210dcc50.link", "final_product/update-version.210dcc50.link") + copyfile("functionary_carl/package.be06db20.link", "final_product/package.be06db20.link") copyfile("functionary_carl/demo-project.tar.gz", "final_product/demo-project.tar.gz") @@ -136,7 +136,7 @@ def supply_chain(): verify_cmd = ("in-toto-verify" " --verbose" " --layout root.layout" - " --layout-key alice.pub") + " --verification-keys alice.pub") print(verify_cmd) retval = subprocess.call(shlex.split(verify_cmd)) @@ -154,17 +154,17 @@ def main(): if args.clean: files_to_delete = [ "owner_alice/root.layout", - "functionary_bob/clone.776a00e2.link", - "functionary_bob/update-version.776a00e2.link", + "functionary_bob/clone.210dcc50.link", + "functionary_bob/update-version.210dcc50.link", "functionary_bob/demo-project", - "functionary_carl/package.2f89b927.link", + "functionary_carl/package.be06db20.link", "functionary_carl/demo-project.tar.gz", "functionary_carl/demo-project", "final_product/alice.pub", "final_product/demo-project.tar.gz", - "final_product/package.2f89b927.link", - "final_product/clone.776a00e2.link", - "final_product/update-version.776a00e2.link", + "final_product/package.be06db20.link", + "final_product/clone.210dcc50.link", + "final_product/update-version.210dcc50.link", "final_product/untar.link", "final_product/root.layout", "final_product/demo-project", @@ -184,5 +184,5 @@ def main(): supply_chain() -if __name__ == '__main__': +if __name__ == '_main_': main() \ No newline at end of file diff --git a/run_demo_md.py b/run_demo_md.py index ba02338..aa19001 100644 --- a/run_demo_md.py +++ b/run_demo_md.py @@ -10,15 +10,15 @@ Provides a script that extracts the demo code snippets from README.md and - runs them in a shell, raising `SystemExit`, if the output is not as expected. + runs them in a shell, raising SystemExit, if the output is not as expected. virtualenv setup and installation of in-toto, as described in the demo instructions, is not performed by this script and must be done before running it. Snippets are run in a temporary directory, which is removed afterwards. - NOTE: Currently, the script runs all snippets marked as `shell` snippets (see - `SNIPPET_PATTERN`). To exclude a snippet from execution it must be marked as - something else (e.g. `bash` to get the same syntax highlighting). + NOTE: Currently, the script runs all snippets marked as shell snippets (see + SNIPPET_PATTERN). To exclude a snippet from execution it must be marked as + something else (e.g. bash to get the same syntax highlighting). """ import os @@ -29,46 +29,39 @@ import difflib import subprocess -# The file pointed to by `INSTRUCTIONS_FN` contains `shell` code snippets that -# may be extracted using the regex defined in `SNIPPET_PATTERN`, and executed -# to generate a combined stdout/stderr equal to `EXPECTED_STDOUT`. +# The file pointed to by INSTRUCTIONS_FN contains shell code snippets that +# may be extracted using the regex defined in SNIPPET_PATTERN, and executed +# to generate a combined stdout/stderr equal to EXPECTED_STDOUT. INSTRUCTIONS_FN = "README.md" -SNIPPET_PATTERN = r"```shell\n([\s\S]*?)\n```" +SNIPPET_PATTERN = r"shell\n([\s\S]*?)\n" EXPECTED_STDOUT = \ """+ cd owner_alice + python create_layout.py Created demo in-toto layout as "root.layout". + cd ../functionary_bob -+ in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --key bob -- git clone https://github.com/in-toto/demo-project.git -'-k', '--key' is deprecated, use '--signing-key' instead. -+ in-toto-record start --step-name update-version --use-dsse --key bob --materials demo-project/foo.py -'-k', '--key' is deprecated, use '--signing-key' instead. ++ in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --signing-key bob -- git clone https://github.com/in-toto/demo-project.git ++ in-toto-record start --step-name update-version --use-dsse --signing-key bob --materials demo-project/foo.py + sed -i.bak s/v0/v1/ demo-project/foo.py + rm demo-project/foo.py.bak -+ in-toto-record stop --step-name update-version --use-dsse --key bob --products demo-project/foo.py -'-k', '--key' is deprecated, use '--signing-key' instead. ++ in-toto-record stop --step-name update-version --use-dsse --signing-key bob --products demo-project/foo.py + cp -r demo-project ../functionary_carl/ + cd ../functionary_carl -+ in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude .git -zcvf demo-project.tar.gz demo-project -'-k', '--key' is deprecated, use '--signing-key' instead. ++ in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude .git -zcvf demo-project.tar.gz demo-project + cd .. -+ cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/update-version.776a00e2.link functionary_carl/package.2f89b927.link functionary_carl/demo-project.tar.gz final_product/ ++ cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ + cd final_product + cp ../owner_alice/alice.pub . -+ in-toto-verify --layout root.layout --layout-key alice.pub -'-k', '--layout-keys' is deprecated, use '--verification-keys' instead. ++ in-toto-verify --layout root.layout --verification-keys alice.pub + echo 0 0 + cd ../functionary_carl + echo something evil -+ in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --key carl -- tar --exclude .git -zcvf demo-project.tar.gz demo-project -'-k', '--key' is deprecated, use '--signing-key' instead. ++ in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude .git -zcvf demo-project.tar.gz demo-project + cd .. -+ cp owner_alice/root.layout functionary_bob/clone.776a00e2.link functionary_bob/update-version.776a00e2.link functionary_carl/package.2f89b927.link functionary_carl/demo-project.tar.gz final_product/ ++ cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ + cd final_product -+ in-toto-verify --layout root.layout --layout-key alice.pub -'-k', '--layout-keys' is deprecated, use '--verification-keys' instead. ++ in-toto-verify --layout root.layout --verification-keys alice.pub (in-toto-verify) RuleVerificationError: 'DISALLOW *' matched the following artifacts: ['demo-project/foo.py'] Full trace for 'expected_materials' of item 'package': Available materials (used for queue): @@ -84,7 +77,7 @@ # Setup a test directory with all necessary demo files and change into it. This # lets us easily clean up all the files created during the demo eventually. -demo_dir = os.path.dirname(os.path.realpath(__file__)) +demo_dir = os.path.dirname(os.path.realpath(_file_)) tmp_dir = os.path.realpath(tempfile.mkdtemp()) test_dir = os.path.join(tmp_dir, os.path.basename(demo_dir)) shutil.copytree(demo_dir, test_dir) @@ -101,8 +94,8 @@ # detailed output and make sure that it has the expected prefix (PS4='+ ') script = "PS4='+ '\nset -x\n{}".format("\n".join(snippets)) - # Execute script in one shell so we can run commands like `cd` - # NOTE: Would be nice to use `in_toto.process.run_duplicate_streams` to show + # Execute script in one shell so we can run commands like cd + # NOTE: Would be nice to use in_toto.process.run_duplicate_streams to show # output in real time, but the method does not support the required kwargs. proc = subprocess.Popen( ["/bin/sh", "-c", script], @@ -127,3 +120,4 @@ # Change back to where we were in the beginning and tear down test directory os.chdir(demo_dir) shutil.rmtree(test_dir) + \ No newline at end of file From 375df933e7a03ae1f5fc589a344224129f16a6d5 Mon Sep 17 00:00:00 2001 From: Dariksha Date: Sat, 18 May 2024 11:42:42 +0530 Subject: [PATCH 6/6] Fixed all the required files Signed-off-by: Dariksha --- README.md | 141 ++++++++++++++++++----------------- owner_alice/create_layout.py | 2 - run_demo.py | 4 +- run_demo_md.py | 23 +++--- 4 files changed, 84 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index ede6a1b..f7a1120 100644 --- a/README.md +++ b/README.md @@ -14,24 +14,24 @@ as the client who verifies the final product. ## Download and setup in-toto on \*NIX (Linux, OS X, ..) -_Virtual Environments (optional)_ +__Virtual Environments (optional)__ -We highly recommend installing in-toto and its dependencies in a -[venv](https://docs.python.org/3/library/venv.html) Python virtual +We highly recommend installing `in-toto` and its dependencies in a +[`venv`](https://docs.python.org/3/library/venv.html) Python virtual environment. Just copy-paste the following snippet to create a virtual environment: -bash +```bash # Create the virtual environment python -m venv in-toto-demo # Activate the virtual environment # This will add the prefix "(in-toto-demo)" to your shell prompt source in-toto-demo/bin/activate +``` - -_Get demo files and install in-toto_ -bash +__Get demo files and install in-toto__ +```bash # Fetch the demo repo using git git clone https://github.com/in-toto/demo.git @@ -40,16 +40,16 @@ cd demo # Install a compatible version of in-toto pip install -r requirements.txt - +``` *Note: If you are having troubles installing in-toto, make sure you have all the system dependencies. See the [installation guide on in-toto.readthedocs.io](https://in-toto.readthedocs.io/en/latest/installing.html) for details.* -Inside the demo directory you will find four directories: owner_alice, -functionary_bob, functionary_carl and final_product. Alice, Bob and Carl +Inside the demo directory you will find four directories: `owner_alice`, +`functionary_bob`, `functionary_carl` and `final_product`. Alice, Bob and Carl already have RSA keys in each of their directories. This is what you see: -bash +```bash tree # If you don't have tree, try 'find .' instead # the tree command gives you the following output # . @@ -68,7 +68,7 @@ tree # If you don't have tree, try 'find .' instead # ├── requirements.txt # ├── run_demo.py # └── run_demo_md.py - +``` ## Run the demo commands Note: if you don't want to type or copy & paste commands and would rather watch @@ -82,153 +82,153 @@ the demo. In this software supply chain layout, we have Alice, who is the project owner that creates the layout, Bob, who clones the project's repo and performs some pre-packaging editing (update version number), and Carl, who uses -tar to package the project sources into a tarball, which +`tar` to package the project sources into a tarball, which together with the in-toto metadata composes the final product that will eventually be installed and verified by the end user. -shell +```shell # Create and sign the software supply chain layout on behalf of Alice cd owner_alice python create_layout.py - +``` The script will create a layout, add Bob's and Carl's public keys (fetched from -their directories), sign it with Alice's private key and dump it to root.layout. -In root.layout, you will find that (besides the signature and other information) -there are three steps, clone, update-version and package, that +their directories), sign it with Alice's private key and dump it to `root.layout`. +In `root.layout`, you will find that (besides the signature and other information) +there are three steps, `clone`, `update-version` and `package`, that the functionaries Bob and Carl, identified by their public keys, are authorized to perform. ### Clone project source code (Bob) Now, we will take the role of the functionary Bob and perform the step -clone on his behalf, that is we use in-toto to clone the project repo from GitHub and +`clone` on his behalf, that is we use in-toto to clone the project repo from GitHub and record metadata for what we do. Execute the following commands to change to Bob's directory and perform the step. -shell +```shell cd ../functionary_bob in-toto-run --step-name clone --use-dsse --products demo-project/foo.py --signing-key bob -- git clone https://github.com/in-toto/demo-project.git - +``` Here is what happens behind the scenes: - 1. In-toto wraps the command git clone https://github.com/in-toto/demo-project.git, - 1. hashes the contents of the source code, i.e. demo-project/foo.py, + 1. In-toto wraps the command `git clone https://github.com/in-toto/demo-project.git`, + 1. hashes the contents of the source code, i.e. `demo-project/foo.py`, 1. adds the hash together with other information to a metadata file, 1. signs the metadata with Bob's private key, and - 1. stores everything to clone.[Bob's keyid].link. + 1. stores everything to `clone.[Bob's keyid].link`. ### Update version number (Bob) Before Carl packages the source code, Bob will update -a version number hard-coded into foo.py. He does this using the in-toto-record command, +a version number hard-coded into `foo.py`. He does this using the `in-toto-record` command, which produces the same link metadata file as above but does not require Bob to wrap his action in a single command. So first Bob records the state of the files he will modify: -shell +```shell # In functionary_bob directory in-toto-record start --step-name update-version --use-dsse --signing-key bob --materials demo-project/foo.py +``` +Then Bob uses an editor of his choice to update the version number in `demo-project/foo.py`, e.g.: -Then Bob uses an editor of his choice to update the version number in demo-project/foo.py, e.g.: - -shell +```shell sed -i.bak 's/v0/v1/' demo-project/foo.py && rm demo-project/foo.py.bak - +``` And finally he records the state of files after the modification and produces -a link metadata file called update-version.[Bob's keyid].link. -shell +a link metadata file called `update-version.[Bob's keyid].link`. +```shell # In functionary_bob directory in-toto-record stop --step-name update-version --use-dsse --signing-key bob --products demo-project/foo.py - +``` Bob has done his work and can send over the sources to Carl, who will create the package for the user. -shell +```shell # Bob has to send the update sources to Carl so that he can package them cp -r demo-project ../functionary_carl/ - +``` ### Package (Carl) -Now, we will perform Carl’s package step by executing the following commands +Now, we will perform Carl’s `package` step by executing the following commands to change to Carl's directory and create a package of the software project -shell +```shell cd ../functionary_carl in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project +``` - -This will create another step link metadata file, called package.[Carl's keyid].link. +This will create another step link metadata file, called `package.[Carl's keyid].link`. It's time to release our software now. ### Verify final product (client) -Let's first copy all relevant files into the final_product that is -our software package demo-project.tar.gz and the related metadata files root.layout, -clone.[Bob's keyid].link, update-version.[Bob's keyid].link and package.[Carl's keyid].link: -shell +Let's first copy all relevant files into the `final_product` that is +our software package `demo-project.tar.gz` and the related metadata files `root.layout`, +`clone.[Bob's keyid].link`, `update-version.[Bob's keyid].link` and `package.[Carl's keyid].link`: +```shell cd .. cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ - +``` And now run verification on behalf of the client: -shell +```shell cd final_product # Fetch Alice's public key from a trusted source to verify the layout signature # Note: The functionary public keys are fetched from the layout cp ../owner_alice/alice.pub . in-toto-verify --layout root.layout --verification-keys alice.pub - +``` This command will verify that 1. the layout has not expired, 2. was signed with Alice’s private key,
and that according to the definitions in the layout 3. each step was performed and signed by the authorized functionary 4. the recorded materials and products follow the artifact rules and - 5. the inspection untar finds what it expects. + 5. the inspection `untar` finds what it expects. -From it, you will see the meaningful output PASSING and a return value -of 0, that indicates verification worked out well: -shell +From it, you will see the meaningful output `PASSING` and a return value +of `0`, that indicates verification worked out well: +```shell echo $? # should output 0 - +``` ### Tampering with the software supply chain Now, let’s try to tamper with the software supply chain. Imagine that someone got a hold of the source code before Carl could package it. -We will simulate this by changing demo-project/foo.py on Carl's machine -(in functionary_carl directory) and then let Carl package and ship the +We will simulate this by changing `demo-project/foo.py` on Carl's machine +(in `functionary_carl` directory) and then let Carl package and ship the malicious code. -shell +```shell cd ../functionary_carl echo something evil >> demo-project/foo.py - +``` Carl thought that this is the genuine code he got from Bob and unwittingly packages the tampered version of foo.py -shell +```shell in-toto-run --step-name package --use-dsse --materials demo-project/foo.py --products demo-project.tar.gz --signing-key carl -- tar --exclude ".git" -zcvf demo-project.tar.gz demo-project - +``` and ships everything out as final product to the client: -shell +```shell cd .. cp owner_alice/root.layout functionary_bob/clone.210dcc50.link functionary_bob/update-version.210dcc50.link functionary_carl/package.be06db20.link functionary_carl/demo-project.tar.gz final_product/ - +``` ### Verifying the malicious product -shell +```shell cd final_product in-toto-verify --layout root.layout --verification-keys alice.pub - -This time, in-toto will detect that the product foo.py from Bob's update-version -step was not used as material in Carl's package step (the verified hashes +``` +This time, in-toto will detect that the product `foo.py` from Bob's `update-version` +step was not used as material in Carl's `package` step (the verified hashes won't match) and therefore will fail verification an return a non-zero value: -shell +```shell echo $? # should output 1 - +``` ### Wrapping up @@ -242,14 +242,15 @@ and how to use it on [in-toto's Github page](https://in-toto.github.io/). ### Clean slate If you want to run the demo again, you can use the following script to remove all the files you created above. -bash +```bash cd .. # You have to be the demo directory python run_demo.py -c - +``` ### Tired of copy-pasting commands? -The same script can be used to sequentially execute all commands listed above. Just change into the demo directory, run python run_demo.py without flags and observe the output. +The same script can be used to sequentially execute all commands listed above. Just change into the `demo` directory, run `python run_demo.py` without flags and observe the output. -bash +```bash # In the demo directory -python run_demo.py +python run_demo.py +``` diff --git a/owner_alice/create_layout.py b/owner_alice/create_layout.py index 630aace..2850afa 100644 --- a/owner_alice/create_layout.py +++ b/owner_alice/create_layout.py @@ -4,7 +4,6 @@ from in_toto.models.metadata import Envelope # https://github.com/in-toto/in-toto/issues/663 from in_toto.models._signer import load_public_key_from_file - def main(): # Load Alice's private key to later sign the layout with open("alice", "rb") as f: @@ -16,7 +15,6 @@ def main(): key_bob = load_public_key_from_file("../functionary_bob/bob.pub") key_carl = load_public_key_from_file("../functionary_carl/carl.pub") - layout = Layout.read({ "_type": "layout", "keys": { diff --git a/run_demo.py b/run_demo.py index a370b20..0a34f24 100644 --- a/run_demo.py +++ b/run_demo.py @@ -184,5 +184,5 @@ def main(): supply_chain() -if __name__ == '_main_': - main() \ No newline at end of file +if __name__ == '__main__': + main() diff --git a/run_demo_md.py b/run_demo_md.py index aa19001..6082fe1 100644 --- a/run_demo_md.py +++ b/run_demo_md.py @@ -10,15 +10,15 @@ Provides a script that extracts the demo code snippets from README.md and - runs them in a shell, raising SystemExit, if the output is not as expected. + runs them in a shell, raising `SystemExit`, if the output is not as expected. virtualenv setup and installation of in-toto, as described in the demo instructions, is not performed by this script and must be done before running it. Snippets are run in a temporary directory, which is removed afterwards. - NOTE: Currently, the script runs all snippets marked as shell snippets (see - SNIPPET_PATTERN). To exclude a snippet from execution it must be marked as - something else (e.g. bash to get the same syntax highlighting). + NOTE: Currently, the script runs all snippets marked as `shell` snippets (see + `SNIPPET_PATTERN`). To exclude a snippet from execution it must be marked as + something else (e.g. `bash` to get the same syntax highlighting). """ import os @@ -29,11 +29,11 @@ import difflib import subprocess -# The file pointed to by INSTRUCTIONS_FN contains shell code snippets that -# may be extracted using the regex defined in SNIPPET_PATTERN, and executed -# to generate a combined stdout/stderr equal to EXPECTED_STDOUT. +# The file pointed to by `INSTRUCTIONS_FN` contains `shell` code snippets that +# may be extracted using the regex defined in `SNIPPET_PATTERN`, and executed +# to generate a combined stdout/stderr equal to `EXPECTED_STDOUT`. INSTRUCTIONS_FN = "README.md" -SNIPPET_PATTERN = r"shell\n([\s\S]*?)\n" +SNIPPET_PATTERN = r"```shell\n([\s\S]*?)\n```" EXPECTED_STDOUT = \ """+ cd owner_alice @@ -77,7 +77,7 @@ # Setup a test directory with all necessary demo files and change into it. This # lets us easily clean up all the files created during the demo eventually. -demo_dir = os.path.dirname(os.path.realpath(_file_)) +demo_dir = os.path.dirname(os.path.realpath(__file__)) tmp_dir = os.path.realpath(tempfile.mkdtemp()) test_dir = os.path.join(tmp_dir, os.path.basename(demo_dir)) shutil.copytree(demo_dir, test_dir) @@ -94,8 +94,8 @@ # detailed output and make sure that it has the expected prefix (PS4='+ ') script = "PS4='+ '\nset -x\n{}".format("\n".join(snippets)) - # Execute script in one shell so we can run commands like cd - # NOTE: Would be nice to use in_toto.process.run_duplicate_streams to show + # Execute script in one shell so we can run commands like `cd` + # NOTE: Would be nice to use `in_toto.process.run_duplicate_streams` to show # output in real time, but the method does not support the required kwargs. proc = subprocess.Popen( ["/bin/sh", "-c", script], @@ -120,4 +120,3 @@ # Change back to where we were in the beginning and tear down test directory os.chdir(demo_dir) shutil.rmtree(test_dir) - \ No newline at end of file