Skip to content

Commit fb414a7

Browse files
authored
Merge pull request #8 from PeterFarber/peterfarber/attest-key
feat(ao_app): added attest_key func to use gotpm attest on 0 padded wallet addr
2 parents b9df2e4 + 41b0126 commit fb414a7

File tree

6 files changed

+335
-18
lines changed

6 files changed

+335
-18
lines changed

DEPLOY-notes.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Deploy notes
2+
3+
This document describes the notes for deploying HyperBEAM using packer.
4+
5+
Packer is a tool that enables a single build to create images for multiple
6+
distribution networks.
7+
8+
The current version is setup for gcp, so you will need to install your gcp.
9+
10+
11+
* https://cloud.google.com/sdk/docs/install
12+
13+
* https://cloud.google.com/sdk/docs/initializing
14+
15+
* https://cloud.google.com/docs/authentication/provide-credentials-adc#how-to
16+
17+
Install Packer
18+
19+
* https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli
20+
21+
```sh
22+
rebar3 clean
23+
rebar3 get-deps
24+
rebar3 compile
25+
rebar3 release
26+
```
27+
28+
```sh
29+
packer init .
30+
packer validate .
31+
packer build .
32+
```
33+
34+
Install go-tpm-tools
35+
Install erlinit
36+
37+
possibly build ao project using nerves
38+
39+
replace /sbin/init with erlinit

GCP-notes.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# GCP & GoTPM Tools
2+
3+
## Table of Contents
4+
5+
- [GCP \& GoTPM Tools](#gcp--gotpm-tools)
6+
- [Table of Contents](#table-of-contents)
7+
- [Variables](#variables)
8+
- [Create an AMD SEV-SNP Instance](#create-an-amd-sev-snp-instance)
9+
- [Create an Intel TDX Instance](#create-an-intel-tdx-instance)
10+
- [Connecting to the Instance](#connecting-to-the-instance)
11+
- [Useful Commands](#useful-commands)
12+
- [List Available Machine Types](#list-available-machine-types)
13+
- [Generate Random Nonces](#generate-random-nonces)
14+
- [Run `gotpm` Attestation](#run-gotpm-attestation)
15+
- [Notes](#notes)
16+
17+
## Variables
18+
19+
```sh
20+
export GCI_NAME=PETES-SEV-SNP-TEST-0
21+
export GCI_PROJECT=arweave-437622
22+
export GCI_IMAGE=packer-1730219529
23+
export GCI_ZONE=us-central1-a
24+
```
25+
26+
## Create an AMD SEV-SNP Instance
27+
28+
```sh
29+
gcloud compute instances create $GCI_NAME \
30+
--zone=$GCI_ZONE \
31+
--machine-type=n2d-standard-2 \
32+
--min-cpu-platform="AMD Milan" \
33+
--confidential-compute-type=SEV_SNP \
34+
--maintenance-policy=TERMINATE \
35+
--image-family=ubuntu-2404-lts-amd64 \
36+
--image-project=ubuntu-os-cloud \
37+
--project=$GCI_PROJECT \
38+
--network-interface=network-tier=PREMIUM,nic-type=GVNIC,stack-type=IPV4_ONLY,subnet=default \
39+
--tags=http-server,https-server \
40+
--shielded-secure-boot \
41+
--shielded-vtpm \
42+
--shielded-integrity-monitoring \
43+
--create-disk=auto-delete=yes,boot=yes,device-name=instance-20241030-131350,image=projects/$GCI_PROJECT/global/images/$GCI_IMAGE,mode=rw,size=20,type=pd-balanced
44+
```
45+
46+
## Create an Intel TDX Instance
47+
48+
```sh
49+
gcloud compute instances create $GCI_NAME \
50+
--zone=$GCI_ZONE \
51+
--machine-type=c3-standard-4 \
52+
--confidential-compute-type=TDX \
53+
--maintenance-policy=TERMINATE \
54+
--image-family=ubuntu-2204-lts \
55+
--image-project=ubuntu-os-cloud \
56+
--project=$GCI_PROJECT \
57+
--network-interface=network-tier=PREMIUM,nic-type=GVNIC,stack-type=IPV4_ONLY,subnet=default \
58+
--tags=http-server,https-server \
59+
--shielded-secure-boot \
60+
--shielded-vtpm \
61+
--shielded-integrity-monitoring \
62+
--create-disk=auto-delete=yes,boot=yes,device-name=instance-20241030-131350,image=projects/$GCI_PROJECT/global/images/$GCI_IMAGE,mode=rw,size=20,type=pd-balanced
63+
```
64+
65+
## Connecting to the Instance
66+
67+
```sh
68+
gcloud compute ssh --zone "$GCI_ZONE" "$GCI_NAME" --project "$GCI_PROJECT"
69+
```
70+
71+
## Useful Commands
72+
73+
### List Available Machine Types
74+
75+
```sh
76+
gcloud compute machine-types list --zones=$GCI_ZONE
77+
```
78+
79+
### Generate Random Nonces
80+
81+
- **32-byte Nonce** (for `--nonce`):
82+
83+
```sh
84+
head -c 32 /dev/urandom | xxd -p -c 64
85+
```
86+
87+
- **64-byte TEE Nonce** (for `--tee-nonce`):
88+
89+
```sh
90+
head -c 64 /dev/urandom | xxd -p -c 128
91+
```
92+
93+
### Run `gotpm` Attestation
94+
95+
```sh
96+
sudo gotpm attest --key AK --nonce <32 bytes (64 hex characters)> --tee-nonce <64 bytes (128 hex characters)> --tee-technology <sev-snp/tdx>
97+
```
98+
99+
## Notes
100+
101+
> [!NOTE]
102+
> The requirement to include both `--nonce` and `--tee-nonce` for the `gotpm attest` command, even when `--tee-technology` (e.g., `sev-snp` or `tdx`) is specified, indicates that **both TPM and TEE layers** of attestation are being validated in this command. Here’s why this is the case:
103+
>
104+
> ### Dual-Layer Attestation in Confidential VMs
105+
>
106+
> **TPM Attestation Layer**:
107+
>
108+
> - The **`--nonce`** parameter is required for the **TPM (Trusted Platform Module) attestation**. It acts as a freshness mechanism for the TPM-based portion of the attestation, preventing replay attacks by ensuring the response is unique to each request.
109+
> - Even when the TEE technology is specified, `gotpm` still performs TPM-based attestation, which includes the TPM nonce (`--nonce`) in the attestation report.
110+
>
111+
> **TEE-Specific Attestation Layer**:
112+
>
113+
> - The **`--tee-nonce`** parameter is required for the **TEE (Trusted Execution Environment) attestation**. This layer provides hardware-backed isolation (e.g., Intel TDX or AMD SEV-SNP), and the larger 64-byte nonce uniquely identifies the TEE attestation report.
114+
> - The `--tee-technology` option (e.g., `sev-snp` or `tdx`) specifies which TEE environment to use, and `--tee-nonce` is essential for proving the freshness of the TEE report in that specific environment.
115+
>
116+
> ### Why Both Nonces Are Required Together
117+
>
118+
> Since the command produces an attestation report containing **both TPM and TEE layers**, each layer requires its own nonce:
119+
>
120+
> - **`--nonce` (TPM layer)**: Required for the general TPM quote in the attestation.
121+
> - **`--tee-nonce` (TEE layer)**: Required specifically for the TEE report tied to `sev-snp` or `tdx`.
122+
>
123+
> This design ensures that the attestation report is comprehensive and includes **freshness proofs** for both the TPM and TEE components, preventing replay attacks across both security layers. This dual nonce requirement is specific to environments where both TPM and TEE attestation are requested together, as in a Confidential VM using TEE.
124+
125+
---

packer.pkr.hcl

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
packer {
2+
required_plugins {
3+
googlecompute = {
4+
version = ">= 1.1.6"
5+
source = "github.com/hashicorp/googlecompute"
6+
}
7+
}
8+
}
9+
10+
# Define required variables
11+
variable "project_id" {
12+
type = string
13+
default = "arweave-437622"
14+
}
15+
16+
variable "region" {
17+
type = string
18+
default = "us-east1"
19+
}
20+
21+
variable "zone" {
22+
type = string
23+
default = "us-east1-c"
24+
}
25+
26+
variable "image_family" {
27+
type = string
28+
default = "ao-image"
29+
}
30+
31+
# Source block to define GCP builder
32+
source "googlecompute" "ubuntu" {
33+
project_id = var.project_id
34+
source_image_family = "ubuntu-2204-lts"
35+
zone = var.zone
36+
machine_type = "n1-standard-1"
37+
ssh_username = "packer"
38+
}
39+
40+
# Define the build stage
41+
build {
42+
sources = ["source.googlecompute.ubuntu"]
43+
44+
# Add a provisioner to download and install go-tpm-tools
45+
provisioner "shell" {
46+
inline = [
47+
"sudo apt-get update -y",
48+
"sudo apt-get install -y wget tar",
49+
50+
# Download the go-tpm-tools binary archive
51+
"wget https://github.com/google/go-tpm-tools/releases/download/v0.4.4/go-tpm-tools_Linux_x86_64.tar.gz -O /tmp/go-tpm-tools.tar.gz",
52+
53+
# Extract the binary
54+
"tar -xzf /tmp/go-tpm-tools.tar.gz -C /tmp",
55+
56+
# Move the gotpm binary to /usr/local/bin
57+
"sudo mv /tmp/gotpm /usr/local/bin/",
58+
59+
# Clean up
60+
"rm -f /tmp/go-tpm-tools.tar.gz /tmp/LICENSE /tmp/README.md"
61+
]
62+
}
63+
64+
65+
# Upload the pre-built release (with ERTS included) to the instance
66+
provisioner "file" {
67+
source = "./_build/default/rel/ao"
68+
destination = "/tmp/ao"
69+
}
70+
71+
provisioner "shell" {
72+
inline = [
73+
# Move the release to /opt with sudo
74+
"sudo mv /tmp/ao /opt/ao",
75+
"sudo chmod -R 755 /opt/ao",
76+
77+
# Create a symlink to make it easier to run the app
78+
"sudo ln -s /opt/ao/bin/ao /usr/local/bin/ao",
79+
80+
# (Optional) If you want to create a systemd service to manage the app
81+
"echo '[Unit]' | sudo tee /etc/systemd/system/ao.service",
82+
"echo 'Description=Permaweb Node' | sudo tee -a /etc/systemd/system/ao.service",
83+
"echo '[Service]' | sudo tee -a /etc/systemd/system/ao.service",
84+
"echo 'Type=simple' | sudo tee -a /etc/systemd/system/ao.service",
85+
"echo 'ExecStart=/opt/ao/bin/ao foreground' | sudo tee -a /etc/systemd/system/ao.service",
86+
"echo 'Restart=on-failure' | sudo tee -a /etc/systemd/system/ao.service",
87+
"echo '[Install]' | sudo tee -a /etc/systemd/system/ao.service",
88+
"echo 'WantedBy=multi-user.target' | sudo tee -a /etc/systemd/system/ao.service",
89+
90+
# Enable and start the service
91+
"sudo systemctl enable ao",
92+
"sudo systemctl start ao"
93+
]
94+
}
95+
96+
# Disable ssh
97+
# provisioner "shell" {
98+
# inline = [
99+
# "sudo systemctl stop ssh",
100+
# "sudo systemctl disable ssh"
101+
# ]
102+
# }
103+
}
104+

rebar.config

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,10 @@
4242
{apps, [ao]}
4343
]}.
4444

45-
{eunit_opts, [verbose]}.
45+
{eunit_opts, [verbose]}.
46+
47+
{relx, [
48+
{release, {'ao', "0.0.1"}, [ao, jiffy, cowboy, gun, gproc, b64fast]},
49+
{include_erts, true},
50+
{extended_start_script, true}
51+
]}.

src/ao_app.erl

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
-behaviour(application).
99

1010
-export([start/2, stop/1]).
11+
-export([attest_key/0]).
1112

1213
-include("include/ao.hrl").
1314

15+
-ao_debug(print).
16+
1417
start(_StartType, _StartArgs) ->
18+
attest_key(),
1519
ao_sup:start_link(),
1620
ok = su_registry:start(),
1721
_TimestampServer = su_timestamp:start(),
@@ -23,23 +27,54 @@ stop(_State) ->
2327
attest_key() ->
2428
W = ao:wallet(),
2529
Addr = ar_wallet:to_address(W),
26-
Cmd = lists:flatten(io_lib:format("...", [])),
27-
case os:cmd(Cmd) of
28-
{ok, Res} ->
29-
Signed = ar_bundle:sign_item(
30-
#tx{
31-
tags = [
32-
{<<"Type">>, <<"TEE-Attestation">>},
33-
{<<"Address">>, ar_util:id(Addr)}
34-
],
35-
data = Res
36-
},
37-
W
38-
),
39-
ao_client:upload(Signed),
40-
ok;
41-
{error, _} ->
42-
skip
30+
31+
% Pad the address to 32 bytes (64 hex characters) for the TPM nonce
32+
Nonce = pad_to_size(Addr, 32),
33+
34+
% Pad the address to 64 bytes (128 hex characters) for the TEE nonce
35+
TeeNonce = pad_to_size(Addr, 64),
36+
37+
% Determine tee-technology based on the existence of TEE devices
38+
TeeTech = case os:cmd("test -e /dev/tdx_guest && echo tdx || (test -e /dev/sev_guest && echo sev-snp)") of
39+
"tdx\n" -> "tdx";
40+
"sev-snp\n" -> "sev-snp";
41+
_ -> {error, "No TEE device found"}
42+
end,
43+
44+
% Proceed if a valid TEE technology is found
45+
case TeeTech of
46+
{error, _} -> {error, "Required TEE device not found"};
47+
_ ->
48+
Cmd = lists:flatten(io_lib:format("sudo gotpm attest --key AK --nonce ~s --tee-nonce ~s --tee-technology ~s", [Nonce, TeeNonce, TeeTech])),
49+
CommandResult = os:cmd(Cmd),
50+
case is_list(CommandResult) of
51+
true ->
52+
% If CommandResult is a list of integers, convert it to binary
53+
BinaryResult = list_to_binary(CommandResult),
54+
?c(BinaryResult),
55+
Signed = ar_bundles:sign_item(
56+
#tx{
57+
tags = [
58+
{<<"Type">>, <<"TEE-Attestation">>},
59+
{<<"Address">>, ar_util:id(Addr)}
60+
],
61+
data = BinaryResult
62+
},
63+
W
64+
),
65+
?c(Signed),
66+
ao_client:upload(Signed),
67+
ok;
68+
false ->
69+
{error, "Unexpected output format from gotpm attest command"}
70+
end
4371
end.
4472

73+
% Pads an address to the specified byte size (in hex characters)
74+
pad_to_size(Addr, SizeInBytes) ->
75+
HexAddr = binary:encode_hex(Addr),
76+
RequiredLength = SizeInBytes * 2, % Convert bytes to hex characters
77+
Padding = RequiredLength - byte_size(HexAddr),
78+
lists:duplicate(Padding, $0) ++ HexAddr.
79+
4580
%% internal functions

src/ar_util.erl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
-export([remove_common/2]).
44
-include("include/ao.hrl").
55

6+
%% @doc Encode an ID in any format to a normalized, b64u 43 character binary.
7+
id(Bin) when is_binary(Bin) andalso byte_size(Bin) == 43 ->
8+
Bin;
9+
id(Bin) when is_binary(Bin) andalso byte_size(Bin) == 32 ->
10+
b64fast:encode(Bin);
11+
id(Data) when is_list(Data) ->
12+
id(list_to_binary(Data)).
13+
614
%% @doc Encode an ID in any format to a normalized, b64u 43 character binary.
715
id(Bin) when is_binary(Bin) andalso byte_size(Bin) == 43 ->
816
Bin;

0 commit comments

Comments
 (0)