Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NOISSUE - Manifest checksum #306

Merged
merged 4 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified attestation.bin
Binary file not shown.
71 changes: 69 additions & 2 deletions cli/checksum.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,93 @@
package cli

import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"os"

"github.com/spf13/cobra"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/internal"
"golang.org/x/crypto/sha3"
)

var (
ismanifest bool
toBase64 bool
)

func (cli *CLI) NewFileHashCmd() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "checksum",
Short: "Compute the sha3-256 hash of a file",
Example: "checksum <file>",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
path := args[0]

if ismanifest {
hash, err := manifestChecksum(path)
if err != nil {
printError(cmd, "Error computing hash: %v ❌ ", err)
return
}

Check warning on line 36 in cli/checksum.go

View check run for this annotation

Codecov / codecov/patch

cli/checksum.go#L34-L36

Added lines #L34 - L36 were not covered by tests

cmd.Println("Hash of manifest file:", hashOut(hash))
return
}

hash, err := internal.ChecksumHex(path)
if err != nil {
printError(cmd, "Error computing hash: %v ❌ ", err)
return
}

cmd.Println("Hash of file:", hash)
cmd.Println("Hash of file:", hashOut(hash))
},
}

cmd.Flags().BoolVarP(&ismanifest, "manifest", "m", false, "Compute the hash of the manifest file")
cmd.Flags().BoolVarP(&toBase64, "base64", "b", false, "Output the hash in base64")

return cmd
}

func manifestChecksum(path string) (string, error) {
file, err := os.ReadFile(path)
if err != nil {
return "", err
}

Check warning on line 62 in cli/checksum.go

View check run for this annotation

Codecov / codecov/patch

cli/checksum.go#L61-L62

Added lines #L61 - L62 were not covered by tests

var cmp agent.Computation

if err := json.Unmarshal(file, &cmp); err != nil {
return "", err
}

jsonBytes, err := json.Marshal(cmp)
if err != nil {
return "", err
}

Check warning on line 73 in cli/checksum.go

View check run for this annotation

Codecov / codecov/patch

cli/checksum.go#L72-L73

Added lines #L72 - L73 were not covered by tests

sum := sha3.Sum256(jsonBytes)

return hex.EncodeToString(sum[:]), nil
}

func hashOut(hashHex string) string {
if toBase64 {
return hexToBase64(hashHex)
}

return hashHex
}

func hexToBase64(hexStr string) string {
decoded, err := hex.DecodeString(hexStr)
if err != nil {
return ""
}

return base64.StdEncoding.EncodeToString(decoded)
}
236 changes: 182 additions & 54 deletions cli/checksum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ package cli

import (
"bytes"
"fmt"
"os"
"strings"
"testing"

"github.com/ultravioletrs/cocos/internal"
"github.com/stretchr/testify/assert"
)

func TestNewFileHashCmd(t *testing.T) {
Expand All @@ -29,74 +30,201 @@ func TestNewFileHashCmd(t *testing.T) {
}

func TestNewFileHashCmdRun(t *testing.T) {
cli := &CLI{}
cmd := cli.NewFileHashCmd()

content := []byte("test content")
tmpfile, err := os.CreateTemp("", "example")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpfile.Name())

if _, err := tmpfile.Write(content); err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
testCases := []struct {
name string
isManifest bool
toBase64 bool
expectedOut string
expectedErr string
}{
{
name: "Valid file",
isManifest: false,
toBase64: false,
expectedOut: "Hash of file:",
expectedErr: "",
},
{
name: "Valid manifest file",
isManifest: true,
toBase64: false,
expectedOut: "Hash of manifest file:",
expectedErr: "",
},
{
name: "Valid file with base64 output",
isManifest: false,
toBase64: true,
expectedOut: "Hash of file:",
expectedErr: "",
},
{
name: "Non-existent file",
isManifest: false,
toBase64: false,
expectedOut: "Error computing hash:",
expectedErr: "",
},
}

var output bytes.Buffer
cmd.SetOut(&output)
cmd.SetErr(&output)

cmd.SetArgs([]string{tmpfile.Name()})
err = cmd.Execute()
if err != nil {
t.Fatalf("Error executing command: %v", err)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cli := &CLI{}
cmd := cli.NewFileHashCmd()

var output bytes.Buffer
cmd.SetOut(&output)
cmd.SetErr(&output)

err := cmd.Flags().Set("manifest", fmt.Sprint(tc.isManifest))
assert.Nil(t, err)
err = cmd.Flags().Set("base64", fmt.Sprint(tc.toBase64))
assert.Nil(t, err)

if tc.name == "Non-existent file" {
cmd.SetArgs([]string{"non_existent_file.txt"})
} else {
content := []byte("{}")
tmpfile, err := os.CreateTemp("", "example")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpfile.Name())

if _, err := tmpfile.Write(content); err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
}

cmd.SetArgs([]string{tmpfile.Name()})
}

err = cmd.Execute()
if err != nil {
t.Fatalf("Error executing command: %v", err)
}

out := output.String()
if !strings.Contains(out, tc.expectedOut) {
t.Errorf("Expected output to contain '%s', got '%s'", tc.expectedOut, out)
}

if tc.expectedErr != "" && !strings.Contains(out, tc.expectedErr) {
t.Errorf("Expected output to contain '%s', got '%s'", tc.expectedErr, out)
}
})
}
}

expectedHash, err := internal.ChecksumHex(tmpfile.Name())
if err != nil {
t.Fatalf("Error computing expected hash: %v", err)
func TestManifestChecksum(t *testing.T) {
testCases := []struct {
name string
jsonContent string
expectedSum string
}{
{
name: "Valid manifest file",
jsonContent: `{
"id": "1234",
"name": "Example Computation",
"description": "This is an example computation"
}`,
expectedSum: "868825367c32c4b6d621d5d95e2890f233d8554df2348ab743aac2663a936f08",
},
{
name: "Invalid JSON",
jsonContent: `{`,
expectedSum: "",
},
}

if !strings.Contains(output.String(), expectedHash) {
t.Errorf("Expected output to contain hash %s, got %s", expectedHash, output.String())
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
f, err := os.CreateTemp("", "test")
assert.Nil(t, err)

t.Cleanup(func() {
os.Remove(f.Name())
})

_, err = f.WriteString(tc.jsonContent)
assert.NoError(t, err)

err = f.Close()
assert.Nil(t, err)

hash, err := manifestChecksum(f.Name())
if tc.expectedSum == "" && err == nil {
t.Errorf("Expected error, got nil")
}
if tc.expectedSum != "" && err != nil {
t.Errorf("Unexpected error: %v", err)
}
if hash != tc.expectedSum {
t.Errorf("Expected hash %s, got %s", tc.expectedSum, hash)
}
})
}
}

func TestNewFileHashCmdInvalidArgs(t *testing.T) {
cli := &CLI{}
cmd := cli.NewFileHashCmd()

err := cmd.Execute()
if err == nil {
t.Error("Expected error when executing without arguments, got nil")
func TestHexToBase64(t *testing.T) {
testCases := []struct {
name string
hexInput string
expectedOut string
}{
{
name: "Valid hex input",
hexInput: "48656c6c6f",
expectedOut: "SGVsbG8=",
},
{
name: "Invalid hex input",
hexInput: "invalid-hex",
expectedOut: "",
},
}

cmd.SetArgs([]string{"file1", "file2"})
err = cmd.Execute()
if err == nil {
t.Error("Expected error when executing with too many arguments, got nil")
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
out := hexToBase64(tc.hexInput)
if out != tc.expectedOut {
t.Errorf("Expected %s, got %s", tc.expectedOut, out)
}
})
}
}

func TestNewFileHashCmdNonExistentFile(t *testing.T) {
cli := &CLI{}
cmd := cli.NewFileHashCmd()

var output bytes.Buffer
cmd.SetOut(&output)
cmd.SetErr(&output)

cmd.SetArgs([]string{"non_existent_file.txt"})
err := cmd.Execute()
if err != nil {
t.Fatalf("Error executing command: %v", err)
func TestHashOut(t *testing.T) {
testCases := []struct {
name string
hashHex string
toBase64 bool
expectedOut string
}{
{
name: "Hex output",
hashHex: "48656c6c6f",
toBase64: false,
expectedOut: "48656c6c6f",
},
{
name: "Base64 output",
hashHex: "48656c6c6f",
toBase64: true,
expectedOut: "SGVsbG8=",
},
}

if !strings.Contains(output.String(), "Error computing hash") {
t.Errorf("Expected output to contain 'Error computing hash', got %s", output.String())
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
toBase64 = tc.toBase64
out := hashOut(tc.hashHex)
if out != tc.expectedOut {
t.Errorf("Expected %s, got %s", tc.expectedOut, out)
}
})
}
}
13 changes: 13 additions & 0 deletions pkg/attestation/quoteprovider/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ package quoteprovider

import (
"github.com/google/go-sev-guest/client"
"github.com/google/go-sev-guest/proto/check"
pb "github.com/google/go-sev-guest/proto/sevsnp"
cocosai "github.com/ultravioletrs/cocos"
)

var (
AttConfigurationSEVSNP = check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}
)

var _ client.QuoteProvider = (*embeddedQuoteProvider)(nil)

type embeddedQuoteProvider struct {
Expand All @@ -36,3 +41,11 @@ func (e *embeddedQuoteProvider) IsSupported() bool {
func (e *embeddedQuoteProvider) Product() *pb.SevProduct {
panic("unimplemented")
}

func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
return cocosai.EmbeddedAttestation, nil
}

func VerifyAttestationReportTLS(attestationBytes []byte, reportData []byte) error {
return nil
}
Loading