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

Clean up and match actual fragments. Don't base64 encode the rego policy. #24

Merged
merged 5 commits into from
Sep 9, 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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...

- name: Test Makafile commands
run: |
cd pkg/cosesign1
make test-all

- name: Test
run: go test -v ./...
3 changes: 2 additions & 1 deletion cmd/sign1util/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ func checkCoseSign1(inputFilename string, chainFilename string, didString string
if err == nil {
fmt.Fprintf(os.Stdout, "DID resolvers passed:\n%s\n", didDoc)
} else {
fmt.Fprintf(os.Stdout, "DID resolvers failed: err: %s doc:\n%s\n", err.Error(), didDoc)
// all the error paths return an empty string, so we can just print the error
fmt.Fprintf(os.Stdout, "DID resolvers failed: err: %s\n", err.Error())
}
}
return unpacked, err
Expand Down
76 changes: 56 additions & 20 deletions pkg/cosesign1/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,44 @@
# will print the new fingerprint of the intermediate cert as part of the did:x509 generated
#


# note test-fail is expected to fail

AUTOPARSE_CHAIN:=0
ISSUER_DID:="TestIssuer"
FEED:="TestFeed"
DID_FINGERPRINT:=""

all: chain.pem cose test-fail test-pass

cose: infra.rego.cose

%.pem:
$(MAKE) -f Makefile.certs chain.pem

ifeq "$(AUTOPARSE_CHAIN)" "1"
ISSUER_DID = $(shell ./sign1util did-x509 -chain chain.pem -policy cn)
DID_FINGERPRINT = $(shell ./sign1util did-x509 -chain chain.pem -policy cn | cut -d: -f5)
endif

# from these media types have to match containerd. The also need to change and the security policy one ought to be x-ms-ccepolicy-frag
# fragment atrifact type = application/x-ms-ccepolicy-frag
# fragment media type = application/cose_x509+rego
# fragment media type = application/cose-x509+rego

# Use a local linux build of the tool for the purposes of this Makefile - ie assume using in wsl.
# Usually sign1util.exe is a windows exe in /mnt/c/ContainerPlat aka c:\ContainerPlat but that is not certain.

sign1util: ../../cmd/sign1util/main.go *.go
go build ../../cmd/sign1util

infra.rego.cose: infra.rego.base64 chain.pem leaf.private.pem sign1util
./sign1util create -algo ES384 -chain chain.pem -claims infra.rego.base64 -key leaf.private.pem -out $@ -issuer TestIssuer -feed TestFeed -salt zero
./sign1util check -in $@
#infra.rego.cose: infra.rego chain.pem leaf.private.pem sign1util
# ./sign1util create -algo ES384 -chain chain.pem -claims infra.rego -key leaf.private.pem -out $@ -issuer TestIssuer -feed TestFeed -salt zero
# ./sign1util check -in $@

%.rego.cose: %.rego chain.pem leaf.private.pem sign1util
./sign1util create -algo ES384 -chain chain.pem -claims $< -key leaf.private.pem -out $@ -salt zero \
-feed $(FEED) -content-type application/unknown+rego \
-issuer $(ISSUER_DID)

print: infra.rego.cose sign1util
./sign1util chain -in $< > tmp.chain.pem
Expand All @@ -51,23 +74,43 @@ show: sign1util
didx509: chain.pem sign1util
./sign1util did-x509 -chain chain.pem -i 1 -policy "subject:CN:Test Leaf (DO NOT TRUST)" -verbose

info: chain.pem sign1util
@echo "ISSUER_DID: $(ISSUER_DID)"
@echo "DID_FINGERPRINT: $(DID_FINGERPRINT)"

# for this to pass the did:x509 fingerprint (RgpNsHOK5hPlCAfTtiGY_BcDhFRxQbJnhlxNDhxps6U here) needs to be the one output from make print
did-check: chain.pem infra.rego.cose sign1util
./sign1util check -in infra.rego.cose -did did:x509:0:sha256:RgpNsHOK5hPlCAfTtiGY_BcDhFRxQbJnhlxNDhxps6U::subject:CN:Test%20Leaf%20%28DO%20NOT%20TRUST%29
did-check: chain.pem infra.rego.cose sign1util info
./sign1util check -in infra.rego.cose -did $(ISSUER_DID)

# For normal workflow start from the chain.pem, here we'd take the chain from inside the cose sign1 doc, eg to manually confirm it is
# as otherwise expected (ie that the issuer DID matches the chain) or to shortcut getting a DID from a cose document.

did-from-cose: sign1util infra.rego.cose
./sign1util did-x509 -in infra.rego.cose -policy cn

did-fail-fingerprint: chain.pem sign1util
./sign1util check -chain chain.pem -in infra.rego.cose -did did:x509:0:sha256:XXXi_nuWegx4NiLaeGabiz36bDUhDDiHEFl8HXMA_4o::subject:CN:Test+Leaf+%28DO+NOT+TRUST%29
# these test changing the fingerprint/sublect to prove failure when the DID is checked against the chain
# note that since the infra.rego.cose is actually good the first part of the check will report a pass "checkCoseSign1 passed"

did-fail-subject: chain.pem sign1util
./sign1util check -chain chain.pem -in infra.rego.cose -did did:x509:0:sha256:RgpNsHOK5hPlCAfTtiGY_BcDhFRxQbJnhlxNDhxps6U::subject:CN:Test+XXXX+%28DO+NOT+TRUST%29
# expect "DID resolvers failed: err: DID verification failed: unexpected certificate fingerprint"
did-fail-fingerprint: chain.pem sign1util infra.rego.cose
./sign1util check -in infra.rego.cose -did did:x509:0:sha256:XXXi_nuWegx4NiLaeGabiz36bDUhDDiHEFl8HXMA_4o::subject:CN:Test+Leaf+%28DO+NOT+TRUST%29

did-fail: did-fail-subject did-fail-fingerprint
# expect "DID resolvers failed: err: DID verification failed: invalid subject value: CN=Test XXXX (DO NOT TRUST)"
did-fail-subject: chain.pem sign1util infra.rego.cose
./sign1util check -in infra.rego.cose -did did:x509:0:sha256:$(DID_FINGERPRINT)::subject:CN:Test+XXXX+%28DO+NOT+TRUST%29

did-fail: did-fail-subject did-fail-fingerprint

# can be confusing
test: test-pass test-fail

test-all: test

# positive tests
test-pass: print show didx509 did-check did-from-cose

# negative tests
test-fail: did-fail


# beyond the scope of this repo
Expand All @@ -80,17 +123,10 @@ did-fail: did-fail-subject did-fail-fingerprint
# --artifact-type application/x-ms-ccepolicy-frag \
# --manifest-config /dev/null:application/vnd.unknown.config.v1+json \
# --subject ${INFRA_IMAGE} \
# ./infra.rego.cose:application/cose_x509+rego

%.pem:
$(MAKE) -f Makefile.certs chain.pem

# ./infra.rego.cose:application/cose-x509+rego

infra.rego.base64: infra.rego
base64 infra.rego > infra.rego.base64

test-all: print show didx509 did-check did-from-cose did-fail

clean:
$(MAKE) -f Makefile.certs $@
rm -f infra.rego.base64 infra.rego.cose sign1util
rm -f infra.rego.cose sign1util
17 changes: 17 additions & 0 deletions pkg/cosesign1/bob.rego
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is adding this intentional? Looks like it's not used by any code. I guess it can be used to try out %.rego.cose though.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package infra

svn := "1"
framework_version := "0.1.0"

containers := [
{
"command": ["python3","infra.py"],
"env_rules": [{"pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "strategy": "string", "required": false},{"pattern": "PYTHONUNBUFFERED=1", "strategy": "string", "required": false},{"pattern": "TERM=xterm", "strategy": "string", "required": false}],
"layers": ["37e9dcf799048b7d35ce53584e0984198e1bc3366c3bb5582fd97553d31beb4e","97112ba1d4a2c86c1c15a3e13f606e8fcc0fb1b49154743cadd1f065c42fee5a","1e66649e162d99c4d675d8d8c3af90ece3799b33d24671bc83fe9ea5143daf2f","3413e98a178646d4703ea70b9bff2d4410e606a22062046992cda8c8aedaa387","b99a9ced77c45fc4dc96bac8ea1e4d9bc1d2a66696cc057d3f3cca79dc999702","e7fbe653352d546497c534c629269c4c04f1997f6892bd66c273f0c9753a4de3","04c110e9406d2b57079f1eac4c9c5247747caa3bcaab6d83651de6e7da97cb40","92e50344671ca5a960887b64c545dbc6d5ca3be82d105c486aabbd381db67578","0a91a3c8a3e80e31a0692609a39e74469119ba071cb0c450a04c86a480345484"],
"mounts": [],
"exec_processes": [],
"signals": [],
"allow_elevated": true,
"working_dir": "/infra"
},
]
26 changes: 17 additions & 9 deletions pkg/cosesign1/cosesign1util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,22 @@ var certChainPEM string

func TestMain(m *testing.M) {
fmt.Println("Generating files...")
makeCleanOut, err := exec.Command("make", "clean").CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to clean up: %s\n", err)
fmt.Fprintf(os.Stderr, string(makeCleanOut))
os.Exit(1)
}

err := exec.Command("make", "chain.pem", "infra.rego.cose").Run()
outputBytes, err := exec.Command("make", "chain.pem", "infra.rego.cose", "leaf.private.pem").CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to build the required test files: %s", err)
fmt.Fprintf(os.Stderr, string(outputBytes))
os.Exit(1)
}
fmt.Println(string(outputBytes))

fragmentRego = readFileStringOrExit("infra.rego.base64")
fragmentRego = readFileStringOrExit("infra.rego")
fragmentCose = readFileBytesOrExit("infra.rego.cose")
leafPrivatePem = readFileStringOrExit("leaf.private.pem")
leafCertPEM = readFileStringOrExit("leaf.cert.pem")
Expand Down Expand Up @@ -85,7 +93,7 @@ func Test_UnpackAndValidateCannedFragment(t *testing.T) {
unpacked, err := UnpackAndValidateCOSE1CertChain(fragmentCose)

if err != nil {
t.Errorf("UnpackAndValidateCOSE1CertChain failed: %s", err.Error())
t.Fatalf("UnpackAndValidateCOSE1CertChain failed: %s", err)
}

iss := unpacked.Issuer
Expand All @@ -101,17 +109,17 @@ func Test_UnpackAndValidateCannedFragment(t *testing.T) {
if !comparePEMs(pubcert, leafCertPEM) {
t.Fatal("pubcert did not match")
}
if cty != "application/unknown+json" {
t.Fatal("cty did not match")
if cty != "application/unknown+rego" {
t.Fatalf("cty did not match: %s", cty)
}
if payload != fragmentRego {
t.Fatal("payload did not match")
}
if iss != "TestIssuer" {
t.Fatal("iss did not match")
t.Fatalf("iss did not match: %s", iss)
}
if feed != "TestFeed" {
t.Fatal("feed did not match")
t.Fatalf("feed did not match: %s", feed)
}
}

Expand All @@ -132,13 +140,13 @@ func Test_UnpackAndValidateCannedFragmentCorrupted(t *testing.T) {

// Use CreateCoseSign1 to make a document that should match the one made by the makefile
func Test_CreateCoseSign1Fragment(t *testing.T) {
var raw, err = CreateCoseSign1([]byte(fragmentRego), "TestIssuer", "TestFeed", "application/unknown+json", []byte(certChainPEM), []byte(leafPrivatePem), "zero", cose.AlgorithmES384)
var raw, err = CreateCoseSign1([]byte(fragmentRego), "TestIssuer", "TestFeed", "application/unknown+rego", []byte(certChainPEM), []byte(leafPrivatePem), "zero", cose.AlgorithmES384)
if err != nil {
t.Fatalf("CreateCoseSign1 failed: %s", err)
}

if len(raw) != len(fragmentCose) {
t.Fatal("created fragment length does not match expected")
t.Fatalf("created fragment length (%d) does not match expected (%d)", len(raw), len(fragmentCose))
}

for i := range raw {
Expand Down
Loading