From 706fb6358866d3509cf9409025bc2350b36c5a15 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 31 Oct 2023 21:31:08 +0530 Subject: [PATCH 01/17] rebase and add tpm policysigning changes --- verification/Makefile | 42 ++++++ verification/README.md | 90 +++++++++++- verification/abi.go | 78 ++++++++++- verification/client.go | 7 + verification/go.mod | 18 ++- verification/go.sum | 39 +++++- verification/tpm.go | 257 +++++++++++++++++++++++++++++++++++ verification/verification.go | 5 + 8 files changed, 520 insertions(+), 16 deletions(-) create mode 100644 verification/Makefile create mode 100644 verification/tpm.go diff --git a/verification/Makefile b/verification/Makefile new file mode 100644 index 00000000..78b7940a --- /dev/null +++ b/verification/Makefile @@ -0,0 +1,42 @@ +# Makefile to install and configure tpm emulator to run Go test verifying Caliptra DPE commands with TPM policy Signing + +SHELL := /bin/bash +SETUP_TPM_EMU_PATH := "/tmp/setup_tpm_emulator" +# Install tpm emulator dependencies +install_dependencies: + sudo apt-get update && \ + sudo apt-get install dh-autoreconf libssl-dev \ + libtasn1-6-dev pkg-config libtpms-dev \ + net-tools iproute2 libjson-glib-dev \ + tar\ + wget\ + git\ + build-essential\ + linux-generic\ + libgnutls28-dev expect gawk socat \ + libseccomp-dev make -y + +# Build and install tpm emulator +run_autogen_and_install: + sudo rm -rf $(SETUP_TPM_EMU_PATH) + mkdir $(SETUP_TPM_EMU_PATH) && cd $(SETUP_TPM_EMU_PATH); \ + git clone https://github.com/stefanberger/swtpm.git; \ + cd swtpm; \ + ./autogen.sh --with-openssl --prefix=/usr; \ + make -j4; \ + make -j4 check; \ + sudo make install + +# Install tpm2-tss +install_tpm2_tss: + sudo apt-get install libjson-c-dev libssl-dev libcurl4-gnutls-dev -y + cd $(SETUP_TPM_EMU_PATH); \ + wget https://github.com/tpm2-software/tpm2-tss/releases/download/3.1.0/tpm2-tss-3.1.0.tar.gz; \ + tar -xzvf tpm2-tss-3.1.0.tar.gz && cd tpm2-tss-3.1.0/ && ./configure && sudo make install && sudo ldconfig + +# Install tpm2-tools +install_tpm2_tools: + sudo apt-get install tpm2-tools + +# The 'setup_tpm_emulator' target runs all steps in order +setup_tpm_emulator: install_dependencies run_autogen_and_install install_tpm2_tss install_tpm2_tools diff --git a/verification/README.md b/verification/README.md index 06e38086..5be607c6 100644 --- a/verification/README.md +++ b/verification/README.md @@ -1,4 +1,90 @@ # DPE Verification Tests -This test suite is a userspace test-suite which exercises DPE commands -end-to-end and ensures compliance with the DPE iRoT Profile. +This test suite is a userspace test-suite which exercises DPE commands end-to-end and ensures compliance with the DPE iRoT Profile. + +## Requirements +* Ubuntu 20 LTS and above +* Golang >= 1.20 +* Make +* Rustup, RustC >= 1.70 + +## Setting up Caliptra DPE Simulator +```sh +git clone https://github.com/chipsalliance/caliptra-dpe.git +cd caliptra-dpe/simulator/ +cargo build +cd ../verification +go test . +``` + +## Setting up TPM emulator +The Software TPM (emulator) is required to run a specific test that verifies Caliptra DPE flow with TPM emulator. +User may choose to configure test requirements either by using Makefile or through command line. + +### Setting up using Makefile +Users may use the target `setup_tpm_emulator` to install and configure TPM emulator. +```sh +# Navigate to verification folder if it is not the current directory +sudo make setup_tpm_emulator +``` +### Setting up using command line +Users may use command line instead of Makefile to install and configure TPM emulator. +If already configured using Makefile, this section shall be skipped and continue with section giving the steps to run the emulator. + +#### Install dependencies +Install the dependencies for software TPM installation. +```sh +sudo apt-get update && \ +sudo apt-get install dh-autoreconf libssl-dev \ + libtasn1-6-dev pkg-config libtpms-dev \ + net-tools iproute2 libjson-glib-dev \ + tar\ + wget\ + git\ + build-essential\ + linux-generic\ + libgnutls28-dev expect gawk socat \ + libseccomp-dev make -y +``` +#### Build TPM emulator +Run autogen.sh, make, check, and install +```sh +export SETUP_TPM_EMU_PATH="/tmp/setup_tpm_emulator" +sudo rm -rf ${SETUP_TPM_EMU_PATH} +mkdir ${SETUP_TPM_EMU_PATH} && cd ${SETUP_TPM_EMU_PATH} +git clone https://github.com/stefanberger/swtpm.git +cd ${SETUP_TPM_EMU_PATH}/swtpm +./autogen.sh --with-openssl --prefix=/usr +make -j4 +make -j4 check +sudo make install +``` +#### Install TPM tools +- Install_tpm2_tss +```sh +sudo apt-get install libjson-c-dev libssl-dev libcurl4-gnutls-dev -y +cd ${SETUP_TPM_EMU_PATH} +wget https://github.com/tpm2-software/tpm2-tss/releases/download/3.1.0/tpm2-tss-3.1.0.tar.gz +tar -xzvf tpm2-tss-3.1.0.tar.gz && cd tpm2-tss-3.1.0/ && ./configure && sudo make install && sudo ldconfig +``` +- Install tpm2-tools +```sh +sudo apt-get install tpm2-tools +``` +### Run TPM emulator +- To run the Go test to verify TPM Policy Signing, start the TPM emulator. +- Open separate terminal instance and issue commands to start. +- When started properly it displays the path of TPM device file. +- Mostly, TPM device path is /dev/tpm0 +```sh +mkdir -p /tmp/myvtpm +sudo modprobe tpm_vtpm_proxy +sudo swtpm chardev --vtpm-proxy --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 +``` +### Run TPM policy signing test +- Open another instance of terminal. +- Run the go test. +```sh +cd caliptra-dpe/verification +sudo go test . -v -tpm-policy-signing-validation="enabled" -tpm-path="/dev/tpm0" +``` diff --git a/verification/abi.go b/verification/abi.go index 57c0d880..3814d56a 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -3,7 +3,6 @@ package verification import ( - "errors" "fmt" "reflect" ) @@ -35,9 +34,13 @@ type Support struct { const ( CommandGetProfile CommandCode = 0x1 CommandInitializeContext CommandCode = 0x7 + CommandDeriveChild CommandCode = 0x8 CommandCertifyKey CommandCode = 0x9 + CommandSign CommandCode = 0xa + CommandRotateContextHandle CommandCode = 0xe CommandDestroyContext CommandCode = 0xf CommandGetCertificateChain CommandCode = 0x80 + CommandExtendTCI CommandCode = 0x81 CommandTagTCI CommandCode = 0x82 CommandGetTaggedTCI CommandCode = 0x83 ) @@ -127,6 +130,25 @@ type CertifyKeyResp[CurveParameter Curve, Digest DigestAlgorithm] struct { Certificate []byte } +type SignFlags uint32 + +const ( + IsSymmetric SignFlags = 1 << 31 // TODO: should be 30, a bug in rust side code. +) + +type SignReq[Digest DigestAlgorithm] struct { + ContextHandle ContextHandle + Label Digest + Flags SignFlags + ToBeSigned Digest +} + +type SignResp[Digest DigestAlgorithm] struct { + NewContextHandle ContextHandle + HmacOrSignatureR Digest + SignatureS Digest +} + type GetCertificateChainReq struct { Offset uint32 Size uint32 @@ -331,6 +353,18 @@ func (c *dpeABI[CurveParameter, Digest]) CertifyKeyABI(cmd *CertifyKeyReq[Digest }, nil } +// Sign calls the DPE Sign command. +func (c *dpeABI[_, Digest]) SignABI(cmd *SignReq[Digest]) (*SignResp[Digest], error) { + var respStruct SignResp[Digest] + + _, err := execCommand(c.transport, CommandSign, c.Profile, cmd, &respStruct) + if err != nil { + return nil, err + } + + return &respStruct, nil +} + // GetCertificateChain calls the DPE GetCertificateChain command. func (c *dpeABI[_, _]) GetCertificateChainABI() (*GetCertificateChainResp, error) { var certs GetCertificateChainResp @@ -365,7 +399,7 @@ func (c *dpeABI[_, _]) GetCertificateChainABI() (*GetCertificateChainResp, error } if len(certs.CertificateChain) == 0 { - return nil, errors.New("empty certificate chain") + return nil, fmt.Errorf("Empty certificate chain returned") } return &certs, nil } @@ -409,6 +443,11 @@ func (c *dpeABI[_, _]) GetProfile() (*GetProfileResp, error) { } func (c *dpeABI[_, Digest]) CertifyKey(handle *ContextHandle, label []byte, format CertifyKeyFormat, flags CertifyKeyFlags) (*CertifiedKey, error) { + + if len(label) != len(Digest(label)) { + return nil, fmt.Errorf("Invalid digest length") + } + cmd := CertifyKeyReq[Digest]{ ContextHandle: *handle, Flags: flags, @@ -416,10 +455,6 @@ func (c *dpeABI[_, Digest]) CertifyKey(handle *ContextHandle, label []byte, form Format: format, } - if len(label) != len(cmd.Label) { - return nil, fmt.Errorf("Invalid digest length") - } - resp, err := c.CertifyKeyABI(&cmd) if err != nil { return nil, err @@ -437,6 +472,37 @@ func (c *dpeABI[_, Digest]) CertifyKey(handle *ContextHandle, label []byte, form return key, nil } +func (c *dpeABI[_, Digest]) Sign(handle *ContextHandle, label []byte, flags SignFlags, toBeSigned []byte) (*DPESignedHash, error) { + + if len(label) != len(Digest(label)) { + return nil, fmt.Errorf("Invalid digest length") + } + + if len(toBeSigned) != len(Digest(toBeSigned)) { + return nil, fmt.Errorf("Invalid toBeSigned length") + } + + cmd := SignReq[Digest]{ + ContextHandle: *handle, + Label: Digest(label), + Flags: flags, + ToBeSigned: Digest(toBeSigned), + } + + resp, err := c.SignABI(&cmd) + if err != nil { + return nil, err + } + + signedResp := &DPESignedHash{ + Handle: resp.NewContextHandle, + HmacOrSignatureR: resp.HmacOrSignatureR.Bytes(), + SignatureS: resp.SignatureS.Bytes(), + } + + return signedResp, nil +} + func (c *dpeABI[_, _]) TagTCI(handle *ContextHandle, tag TCITag) (*ContextHandle, error) { cmd := TagTCIReq{ ContextHandle: *handle, diff --git a/verification/client.go b/verification/client.go index 96cde995..e4e4a060 100755 --- a/verification/client.go +++ b/verification/client.go @@ -33,6 +33,12 @@ type DPETCI struct { CurrentTCI []byte } +type DPESignedHash struct { + Handle ContextHandle + HmacOrSignatureR []byte + SignatureS []byte +} + type DPEClient interface { InitializeContext(flags InitCtxFlags) (*ContextHandle, error) GetProfile() (*GetProfileResp, error) @@ -41,6 +47,7 @@ type DPEClient interface { TagTCI(handle *ContextHandle, tag TCITag) (*ContextHandle, error) GetTaggedTCI(tag TCITag) (*DPETCI, error) DestroyContext(handle *ContextHandle, flags DestroyCtxFlags) error + Sign(handle *ContextHandle, label []byte, flags SignFlags, toBeSigned []byte) (*DPESignedHash, error) } func NewClient(t Transport, p Profile) (DPEClient, error) { diff --git a/verification/go.mod b/verification/go.mod index f88413a8..06f549c7 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -3,15 +3,25 @@ module github.com/chipsalliance/caliptra-dpe/verification go 1.20 require ( + github.com/google/go-tpm v0.9.0 + github.com/google/go-tpm-tools v0.4.1 github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 github.com/zmap/zlint/v3 v3.4.1 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 ) require ( + github.com/google/go-sev-guest v0.7.0 // indirect + github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84 // indirect + github.com/google/logger v1.1.1 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/pborman/uuid v1.2.0 // indirect github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.11.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/verification/go.sum b/verification/go.sum index 59288fa6..08058358 100644 --- a/verification/go.sum +++ b/verification/go.sum @@ -6,12 +6,30 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= +github.com/google/go-attestation v0.5.0 h1:jXtAWT2sw2Yu8mYU0BC7FDidR+ngxFPSE+pl6IUu3/0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-sev-guest v0.7.0 h1:DBCABhTo7WicP27ZH/hwcCdjcmxFkxxMOQXm5hFcfp4= +github.com/google/go-sev-guest v0.7.0/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= +github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84 h1:XqVJa7fVU8b+Hlhcvw49qfg0+LYcRI+V+jYUrSek848= +github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84/go.mod h1:a8EIh1l5x7jmIrrOuH//xWn6y4Sk4yupwmMcJE006RI= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= +github.com/google/go-tpm-tools v0.4.1 h1:gYU6iwRo0tY3V6NDnS6m+XYog+b3g6YFhHQl3sYaUL4= +github.com/google/go-tpm-tools v0.4.1/go.mod h1:w03m0jynhTo7puXTYoyfpNOMqyQ9SB7sixnKWsS/1L0= +github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= +github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= +github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -21,8 +39,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -32,8 +54,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= @@ -49,6 +71,7 @@ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.4.1 h1:zhGB2Q1oPNS+bODC5tTPlKDOnLfDGyxejgAEp1SfFiQ= github.com/zmap/zlint/v3 v3.4.1/go.mod h1:WgepL2QqxyMHnrOWJ54NqrgfMtOyuXr52wEE0tcfo9k= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -57,8 +80,9 @@ golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -71,8 +95,9 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -85,12 +110,15 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -102,8 +130,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -115,6 +144,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/verification/tpm.go b/verification/tpm.go new file mode 100644 index 00000000..b3c2f62b --- /dev/null +++ b/verification/tpm.go @@ -0,0 +1,257 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "crypto/ecdsa" + "crypto/sha256" + "crypto/sha512" + "crypto/x509" + "encoding/binary" + "flag" + "io" + "math" + "math/big" + "strings" + "testing" + + "github.com/google/go-tpm-tools/client" + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/tpmutil" +) + +var ( + tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).") + tpmPolicySigningValidation = flag.String("tpm-policy-signing-validation", "disabled", "Validation of TPM policy signing with Caliptra DPE commands is enabled/disabled. By default, this is disabled.") + + handleNames = map[string][]tpm2.HandleType{ + "all": {tpm2.HandleTypeLoadedSession, tpm2.HandleTypeSavedSession, tpm2.HandleTypeTransient}, + "loaded": {tpm2.HandleTypeLoadedSession}, + "saved": {tpm2.HandleTypeSavedSession}, + "transient": {tpm2.HandleTypeTransient}, + } +) + +func TestTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { + if strings.ToLower(*tpmPolicySigningValidation) == "enabled" { + t.Log("Validation of TPM policy signing using Caliptra DPE commands is enabled.") + testTpmPolicySigning(d, c, t) + } else { + t.Log("Validation of TPM policy signing using Caliptra DPE commands is disabled, skipping this test.\n To enable this validation start the TPM emulator, set `go test . -tpm-policy-signing-validation=enabled` and rerun.") + return + } +} + +func flushAllContexts(t *testing.T, tpm io.ReadWriteCloser) { + totalHandles := 0 + for _, handleType := range handleNames["all"] { + handles, err := client.Handles(tpm, handleType) + if err != nil { + t.Fatalf("[FATAL]: Error getting handles %s: %v", *tpmPath, err) + } + for _, handle := range handles { + if err = tpm2.FlushContext(tpm, handle); err != nil { + t.Fatalf("[FATAL]: Error flushing handle 0x%x: %v", handle, err) + } + t.Logf("Handle 0x%x flushed", handle) + totalHandles++ + } + } +} + +func startTpmSession(t *testing.T, tpm io.ReadWriteCloser, alg tpm2.Algorithm) (tpmutil.Handle, []byte, error) { + + flushAllContexts(t, tpm) + sessHandle, nonce, err := tpm2.StartAuthSession(tpm, + tpm2.HandleNull, + tpm2.HandleNull, + make([]byte, 16), + nil, + tpm2.SessionPolicy, + tpm2.AlgNull, + alg) + + if err != nil { + t.Fatalf("[FATAL]: StartAuthSession() failed: %v", err) + } + + return sessHandle, nonce, nil +} + +func testTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { + var ctx ContextHandle = [16]byte{0} + var ec tpm2.EllipticCurve + var alg tpm2.Algorithm + + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + digestLen := profile.GetDigestSize() + + if digestLen == len(SHA256Digest{0}) { + alg = tpm2.AlgSHA256 + ec = tpm2.CurveNISTP256 + } else if digestLen == len(SHA384Digest{0}) { + alg = tpm2.AlgSHA384 + ec = tpm2.CurveNISTP384 + } + + //Create tpm auth session to get nonce and form label which is digest + tpm, err := tpm2.OpenTPM(*tpmPath) + if err != nil { + t.Fatalf("[FATAL]: Can't open TPM %s: %v", *tpmPath, err) + } + + sessHandle, nonce, err := startTpmSession(t, tpm, alg) + if err != nil { + t.Fatalf("[FATAL]: Error in getting tpm nonce") + } + + defer func() { + if err := tpm.Close(); err != nil { + t.Fatalf("[FATAL]: Can't close TPM %s: %v", *tpmPath, err) + } + }() + + defer tpm2.FlushContext(tpm, sessHandle) + + // Build SignHash request + expiry := int32(math.MinInt32) + digest := getDigest(nonce, expiry, digestLen) + + seqLabel := make([]byte, digestLen) + for i, _ := range seqLabel { + seqLabel[i] = byte(i) + } + + // Get signed hash from DPE + signResp, err := c.Sign(&ctx, seqLabel, SignFlags(0), digest) + if err != nil { + t.Fatalf("[FATAL]: Could not sign: %v", err) + } + + certifyKeyResp, err := c.CertifyKey(&(signResp.Handle), seqLabel, CertifyKeyX509, CertifyKeyFlags(0)) + if err != nil { + t.Fatalf("[FATAL]: Could not CertifyKey: %v", err) + } + + pubKey := extractPubKey(t, certifyKeyResp.Certificate) + + // Get TPM handle loaded with public key + pkh := loadPubKey(t, pubKey, tpm, alg, ec) + + // Get encoded signature from TPM + r := new(big.Int).SetBytes(signResp.HmacOrSignatureR) + s := new(big.Int).SetBytes(signResp.SignatureS) + + encodedSignature := getEncodedSignature(t, r, s, alg) + + // Verify Policy with Signature + _, _, err = tpm2.PolicySigned(tpm, pkh, sessHandle, nonce, nil, nil, expiry, encodedSignature) + if err != nil { + t.Fatalf("[FATAL]: PolicySigned() failed: %v", err) + } + + t.Log("[LOG]: PolicySigned() call success") +} + +func getDigest(nonce []byte, expiry int32, digestLen int) []byte { + + expBytes := make([]byte, 4) + binary.BigEndian.PutUint32(expBytes, uint32(expiry)) + + toDigest := append(nonce, expBytes...) + + digest := make([]byte, digestLen) + if digestLen == len(SHA256Digest{0}) { + hash := sha256.Sum256(toDigest) + digest = hash[:] + } else if digestLen == len(SHA384Digest{0}) { + hash := sha512.Sum384(toDigest) + digest = hash[:] + } + return digest +} + +func extractPubKey(t *testing.T, leafBytes []byte) *ecdsa.PublicKey { + var x509Cert *x509.Certificate + var err error + + t.Log("[LOG]: Parse the obtained certificate...") + // Check whether certificate is DER encoded. + if x509Cert, err = x509.ParseCertificate(leafBytes); err != nil { + t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) + } + + publicKeyDer, err := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) + if err != nil { + t.Fatalf("[FATAL]: Could not marshal pub key: %v", err) + } + + // Parse the DER-encoded public key + pubKey, err := x509.ParsePKIXPublicKey(publicKeyDer) + if err != nil { + t.Fatalf("[FATAL]: Failed to parse DER-encoded public key: %v", err) + } + + if _, ok := pubKey.(*ecdsa.PublicKey); !ok { + t.Fatal("[FATAL]: Public key is not a ecdsa key") + } + + return pubKey.(*ecdsa.PublicKey) +} + +func loadPubKey(t *testing.T, pubKey any, tpm io.ReadWriteCloser, alg tpm2.Algorithm, ec tpm2.EllipticCurve) tpmutil.Handle { + var tpmPublic tpm2.Public + + // Create a tpm2.Public structure from the parsed ECDSA public key + switch pubKey := pubKey.(type) { + case *ecdsa.PublicKey: + tpmPublic = tpm2.Public{ + Type: tpm2.AlgECC, // ECDSA key type + NameAlg: alg, + Attributes: tpm2.FlagSign | tpm2.FlagSensitiveDataOrigin | tpm2.FlagUserWithAuth, + ECCParameters: &tpm2.ECCParams{ + Sign: &tpm2.SigScheme{ + Alg: tpm2.AlgECDSA, + Hash: alg, + }, + CurveID: ec, + Point: tpm2.ECPoint{ + XRaw: new(big.Int).SetBytes(pubKey.X.Bytes()).Bytes(), + YRaw: new(big.Int).SetBytes(pubKey.Y.Bytes()).Bytes(), + }, + }, + } + default: + t.Fatalf("[FATAL]: Unsupported public key type") + } + + t.Logf("[LOG]: TPM2 Public Key: %v", tpmPublic) + + pkh, _, err := tpm2.LoadExternal(tpm, tpmPublic, tpm2.Private{}, tpm2.HandleNull) + if err != nil { + t.Fatalf("[FATAL]: Unable to load eexternal public key. Error: %v", err) + } + + return pkh +} + +func getEncodedSignature(t *testing.T, r *big.Int, s *big.Int, alg tpm2.Algorithm) []byte { + signature := tpm2.Signature{ + Alg: tpm2.AlgECDSA, + ECC: &tpm2.SignatureECC{ + HashAlg: alg, + R: r, + S: s, + }, + } + encodedSign, err := signature.Encode() + if err != nil { + t.Fatalf("[FATAL]: Unable to encode signature: %v", err) + } + t.Logf("[LOG]: Encoded Signature is %s", string(encodedSign)) + + return encodedSign +} diff --git a/verification/verification.go b/verification/verification.go index 4e2b0c06..ef5652db 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -40,10 +40,15 @@ var GetProfileTestCase = TestCase{ "GetProfile", TestGetProfile, []string{}, } +var TpmPolicySigningTestCase = TestCase{ + "TPMPolicySigning", TestTpmPolicySigning, []string{"AutoInit", "X509"}, +} + var AllTestCases = []TestCase{ CertifyKeyTestCase, CertifyKeySimulationTestCase, GetCertificateChainTestCase, + TpmPolicySigningTestCase, TagTCITestCase, GetProfileTestCase, InitializeContextTestCase, From c45596eb874ba04c8d2eafcab689847687613594 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 31 Oct 2023 23:57:45 +0530 Subject: [PATCH 02/17] rebase --- verification/tpm.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/verification/tpm.go b/verification/tpm.go index b3c2f62b..761dd77a 100644 --- a/verification/tpm.go +++ b/verification/tpm.go @@ -53,7 +53,6 @@ func flushAllContexts(t *testing.T, tpm io.ReadWriteCloser) { if err = tpm2.FlushContext(tpm, handle); err != nil { t.Fatalf("[FATAL]: Error flushing handle 0x%x: %v", handle, err) } - t.Logf("Handle 0x%x flushed", handle) totalHandles++ } } @@ -121,7 +120,7 @@ func testTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { digest := getDigest(nonce, expiry, digestLen) seqLabel := make([]byte, digestLen) - for i, _ := range seqLabel { + for i := range seqLabel { seqLabel[i] = byte(i) } @@ -153,7 +152,7 @@ func testTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { t.Fatalf("[FATAL]: PolicySigned() failed: %v", err) } - t.Log("[LOG]: PolicySigned() call success") + t.Log("PolicySigning validation is successful") } func getDigest(nonce []byte, expiry int32, digestLen int) []byte { @@ -178,7 +177,6 @@ func extractPubKey(t *testing.T, leafBytes []byte) *ecdsa.PublicKey { var x509Cert *x509.Certificate var err error - t.Log("[LOG]: Parse the obtained certificate...") // Check whether certificate is DER encoded. if x509Cert, err = x509.ParseCertificate(leafBytes); err != nil { t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) @@ -228,8 +226,6 @@ func loadPubKey(t *testing.T, pubKey any, tpm io.ReadWriteCloser, alg tpm2.Algor t.Fatalf("[FATAL]: Unsupported public key type") } - t.Logf("[LOG]: TPM2 Public Key: %v", tpmPublic) - pkh, _, err := tpm2.LoadExternal(tpm, tpmPublic, tpm2.Private{}, tpm2.HandleNull) if err != nil { t.Fatalf("[FATAL]: Unable to load eexternal public key. Error: %v", err) @@ -251,7 +247,5 @@ func getEncodedSignature(t *testing.T, r *big.Int, s *big.Int, alg tpm2.Algorith if err != nil { t.Fatalf("[FATAL]: Unable to encode signature: %v", err) } - t.Logf("[LOG]: Encoded Signature is %s", string(encodedSign)) - return encodedSign } From ff7e4b1e900932793358c04f8a6173c18f915128 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Thu, 2 Nov 2023 19:08:16 +0530 Subject: [PATCH 03/17] deriveChild commit with a bug fix --- verification/abi.go | 114 +++++++- verification/certifyKey.go | 437 +++++++++++++++++++++++------- verification/client.go | 2 + verification/deriveChild.go | 274 +++++++++++++++++++ verification/initializeContext.go | 25 ++ verification/simulator.go | 7 +- verification/verification.go | 14 +- 7 files changed, 769 insertions(+), 104 deletions(-) create mode 100644 verification/deriveChild.go diff --git a/verification/abi.go b/verification/abi.go index 3814d56a..f01d0a7e 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -7,6 +7,8 @@ import ( "reflect" ) +var DefaultContextHandle = ContextHandle{0} + const ( CmdMagic uint32 = 0x44504543 RespMagic uint32 = 0x44504552 @@ -70,6 +72,21 @@ const ( type ContextHandle [16]byte +type RotateContextHandleFlags uint32 + +const ( + TargetIsDefault RotateContextHandleFlags = 1 << 31 +) + +type RotateContextHandleCmd struct { + Handle ContextHandle + Flags RotateContextHandleFlags +} + +type RotatedContextHandle struct { + NewContextHandle ContextHandle +} + type DestroyCtxFlags uint32 const ( @@ -103,6 +120,31 @@ type GetProfileResp struct { Flags uint32 } +type DeriveChildFlags uint32 + +const ( + InternalInputInfo DeriveChildFlags = 1 << 31 + InternalInputDice DeriveChildFlags = 1 << 30 + RetainParent DeriveChildFlags = 1 << 29 + MakeDefault DeriveChildFlags = 1 << 28 + ChangeLocality DeriveChildFlags = 1 << 27 + InputAllowCA DeriveChildFlags = 1 << 26 + InputAllowX509 DeriveChildFlags = 1 << 25 +) + +type DeriveChildReq[Digest DigestAlgorithm] struct { + ContextHandle ContextHandle + InputData Digest + Flags DeriveChildFlags + TciType uint32 + TargetLocality uint32 +} + +type DeriveChildResp struct { + NewContextHandle ContextHandle + ParentContextHandle ContextHandle +} + type CertifyKeyFlags uint32 const ( @@ -213,12 +255,12 @@ func dpeProfileImplementsTypeConstraints[C Curve, D DigestAlgorithm](profile Pro } else if isP384 && isSHA384 { targetProfile = ProfileP384SHA384 } else { - return fmt.Errorf("Client requested (Curve = %v, Digest = %v), this is an invalid DPE profile", + return fmt.Errorf("client requested (Curve = %v, Digest = %v), this is an invalid DPE profile", reflect.TypeOf(c), reflect.TypeOf(d)) } if profile != targetProfile { - fmt.Errorf("Expected profile %v, got profile %v", targetProfile, profile) + return fmt.Errorf("expected profile %v, got profile %v", targetProfile, profile) } return nil @@ -353,6 +395,30 @@ func (c *dpeABI[CurveParameter, Digest]) CertifyKeyABI(cmd *CertifyKeyReq[Digest }, nil } +// DeriveChild calls DPE DeriveChild command. +func (c *dpeABI[_, Digest]) DeriveChildABI(cmd *DeriveChildReq[Digest]) (*DeriveChildResp, error) { + var respStruct DeriveChildResp + + _, err := execCommand(c.transport, CommandDeriveChild, c.Profile, cmd, &respStruct) + if err != nil { + return nil, err + } + + return &respStruct, err +} + +// DeriveChild calls DPE RotateContextABI command. +func (c *dpeABI[_, Digest]) RotateContextABI(cmd *RotateContextHandleCmd) (*RotatedContextHandle, error) { + var respStruct RotatedContextHandle + + _, err := execCommand(c.transport, CommandRotateContextHandle, c.Profile, cmd, &respStruct) + if err != nil { + return nil, err + } + + return &respStruct, err +} + // Sign calls the DPE Sign command. func (c *dpeABI[_, Digest]) SignABI(cmd *SignReq[Digest]) (*SignResp[Digest], error) { var respStruct SignResp[Digest] @@ -399,7 +465,7 @@ func (c *dpeABI[_, _]) GetCertificateChainABI() (*GetCertificateChainResp, error } if len(certs.CertificateChain) == 0 { - return nil, fmt.Errorf("Empty certificate chain returned") + return nil, fmt.Errorf("empty certificate chain returned") } return &certs, nil } @@ -443,9 +509,8 @@ func (c *dpeABI[_, _]) GetProfile() (*GetProfileResp, error) { } func (c *dpeABI[_, Digest]) CertifyKey(handle *ContextHandle, label []byte, format CertifyKeyFormat, flags CertifyKeyFlags) (*CertifiedKey, error) { - if len(label) != len(Digest(label)) { - return nil, fmt.Errorf("Invalid digest length") + return nil, fmt.Errorf("invalid digest length") } cmd := CertifyKeyReq[Digest]{ @@ -472,14 +537,46 @@ func (c *dpeABI[_, Digest]) CertifyKey(handle *ContextHandle, label []byte, form return key, nil } -func (c *dpeABI[_, Digest]) Sign(handle *ContextHandle, label []byte, flags SignFlags, toBeSigned []byte) (*DPESignedHash, error) { +func (c *dpeABI[_, Digest]) DeriveChild(handle *ContextHandle, inputData []byte, flags DeriveChildFlags, tciType uint32, targetLocality uint32) (*DeriveChildResp, error) { + cmd := DeriveChildReq[Digest]{ + ContextHandle: *handle, + InputData: Digest(inputData), + Flags: flags, + TciType: tciType, + TargetLocality: targetLocality, + } + + if len(inputData) != len(cmd.InputData) { + return nil, fmt.Errorf("invalid digest length") + } + + resp, err := c.DeriveChildABI(&cmd) + if err != nil { + return nil, err + } + + return resp, nil +} +func (c *dpeABI[_, _]) RotateContextHandle(handle *ContextHandle, flags RotateContextHandleFlags) (*ContextHandle, error) { + cmd := RotateContextHandleCmd{ + Handle: *handle, + Flags: flags, + } + resp, err := c.RotateContextABI(&cmd) + if err != nil { + return nil, err + } + return &resp.NewContextHandle, nil +} + +func (c *dpeABI[_, Digest]) Sign(handle *ContextHandle, label []byte, flags SignFlags, toBeSigned []byte) (*DPESignedHash, error) { if len(label) != len(Digest(label)) { - return nil, fmt.Errorf("Invalid digest length") + return nil, fmt.Errorf("invalid digest length") } if len(toBeSigned) != len(Digest(toBeSigned)) { - return nil, fmt.Errorf("Invalid toBeSigned length") + return nil, fmt.Errorf("invalid toBeSigned length") } cmd := SignReq[Digest]{ @@ -488,7 +585,6 @@ func (c *dpeABI[_, Digest]) Sign(handle *ContextHandle, label []byte, flags Sign Flags: flags, ToBeSigned: Digest(toBeSigned), } - resp, err := c.SignABI(&cmd) if err != nil { return nil, err diff --git a/verification/certifyKey.go b/verification/certifyKey.go index 3e83e05d..b14ed70f 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -4,11 +4,17 @@ package verification import ( "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha256" + "crypto/sha512" "crypto/x509" "encoding/asn1" "encoding/binary" "encoding/pem" + "errors" "fmt" + "math/big" "reflect" "testing" "time" @@ -34,6 +40,8 @@ var ( OidExtensionTcgDiceKpAssertInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 10} OidExtensionTcgDiceKpAssertLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 11} OidExtensionTcgDiceKpEca = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 12} + OidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} + OidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} ) var TcgDiceCriticalExtensions = [...]string{ @@ -115,18 +123,211 @@ const ( type TcgMultiTcbInfo = []DiceTcbInfo +type CertifyKeyParams struct { + Label []byte + Flags CertifyKeyFlags +} + func TestCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T) { testCertifyKey(d, c, t, false) } -func TestCertifyKey_SimulationMode(d TestDPEInstance, c DPEClient, t *testing.T) { +func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { testCertifyKey(d, c, t, true) } +func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { + handle := getContextHandle(d, c, t, simulation) + targetLocality := DPE_SIMULATOR_AUTO_INIT_LOCALITY + if simulation { + targetLocality = DPE_SIMULATOR_OTHER_LOCALITY + defer c.DestroyContext(handle, 0) + } + + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + digestLen := profile.GetDigestSize() + + // Test wrong locality for autoinitialized context + if !simulation { + testWrongLocalityForCertifyKey(d, c, t, handle) + } + + var hashAlg asn1.ObjectIdentifier + if digestLen == 32 { + hashAlg = OidSHA256 + } else if digestLen == 48 { + hashAlg = OidSHA384 + } else { + t.Fatal("Unknown Hash Algorithm") + } + + seqLabel := make([]byte, digestLen) + for i := range seqLabel { + seqLabel[i] = byte(i) + } + + certifyKeyParams := []CertifyKeyParams{ + {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, + {Label: seqLabel, Flags: CertifyKeyFlags(0)}, + } + + for _, params := range certifyKeyParams { + + // Get DPE leaf certificate from CertifyKey + certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) + if err != nil { + t.Fatalf("[FATAL]: Could not certify key: %v", err) + } + + // Get root and intermediate certificates to validate certificate chain of leaf cert + certChainBytes, err := c.GetCertificateChain() + if err != nil { + t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) + } + + leafCertBytes := certifyKeyResp.Certificate + + // Run X.509 linter on full certificate chain and file issues for errors + leafCert := checkCertificateStructure(t, leafCertBytes) + certChain := checkCertificateChain(t, certChainBytes) + + // Check key returned in command response against certificate + checkCertifyKeyResponse(t, leafCert, *certifyKeyResp, hashAlg) + + // Check for basic constraints extension + checkCertifyKeyBasicConstraints(t, leafCert, params.Flags) + + // Check key usage extensions - DigitalSignature, CertSign + checkCertifyKeyExtensions(t, leafCert) + + // Check extended key usage extensions + checkCertifyKeyExtendedKeyUsages(t, leafCert) + + // Check critical UEID and Multi Tcb Info TCG extensions + // Check UEID extension + checkCertifyKeyTcgUeidExtension(t, leafCert, params.Label) + + // Check MultiTcbInfo Extension structure + multiTcbInfo, err := checkCertifyKeyMultiTcbInfoExtensionStructure(t, leafCert) + if err != nil { + t.Errorf("Error while unmarshalling MultiTCB information %v, skipping MultiTCB validation", err) + } else { + // Check type field + checkCurrentDiceTcbTciType(t, multiTcbInfo, 0) + // Check vendorInfo field + checkDiceTcbVendorInfo(t, multiTcbInfo, targetLocality) + // Check hash algorithm + checkDiceTcbHashAlgorithm(t, multiTcbInfo, hashAlg) + } + + // Ensure full certificate chain has valid signatures + // This also checks certificate lifetime, signatures as part of cert chain validation + checkLeafCertChain(t, certChain, leafCert) + + if simulation { + handle = &certifyKeyResp.Handle + } + } + // DeriveChild to add more TCIs and call CertifyKey again. + checkWithDerivedChildContext(d, c, t, digestLen, hashAlg, handle, simulation) +} + +// Checks whether error is reported when caller from one locality uses another locality +func testWrongLocalityForCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) { + var err error + + // Modify locality of DPE instance to test + d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) + + // Restore locality of DPE instance after the test + defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyKeyFlags(0)) + if err == nil { + t.Fatalf("[FATAL]: CertifyKey command should return %q, but returned no error", StatusInvalidLocality) + } else if !errors.Is(err, StatusInvalidLocality) { + t.Fatalf("[FATAL]: Incorrect error type. CertifyKey command should return %q, but returned %q", StatusInvalidLocality, err) + } +} + +// Check CertifyKey command after adding more TCIs by DeriveChild command. +// The MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. +// In a DiceTcbInfo block of a given TCI node, +// the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. +// the "fwid" field must contain cumulative TCI measurement. +func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, digestLen int, hashAlg asn1.ObjectIdentifier, handle *ContextHandle, simulation bool) { + targetLocality := DPE_SIMULATOR_AUTO_INIT_LOCALITY + if simulation { + targetLocality = DPE_SIMULATOR_OTHER_LOCALITY + } + + seqLabel := make([]byte, digestLen) + for i := range seqLabel { + seqLabel[i] = byte(i) + } + + tciType := uint32(1) + dc, err := c.DeriveChild(handle, + seqLabel, + InputAllowX509, + tciType, + DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + if err != nil { + t.Fatalf("[FATAL]: Derive child command failed with error: %v", err) + } + + // Get DPE leaf certificate from CertifyKey + certifyKeyResp, err := c.CertifyKey(&dc.NewContextHandle, + seqLabel, + CertifyKeyX509, + CertifyKeyFlags(0)) + if err != nil { + t.Fatalf("[FATAL]: Could not certify key using derived child context handle: %v", err) + } + leafCertBytes := certifyKeyResp.Certificate + + // Run X.509 linter on full certificate chain and file issues for errors + leafCert := checkCertificateStructure(t, leafCertBytes) + + // Check MultiTcbInfo Extension structure + multiTcbInfo, err := checkCertifyKeyMultiTcbInfoExtensionStructure(t, leafCert) + if err != nil { + t.Errorf("Error while unmarshalling MultiTCB information %v, skipping MultiTCB validation", err) + } else { + // Check vendorInfo field + checkDiceTcbVendorInfo(t, multiTcbInfo, targetLocality) + // Check type field + checkCurrentDiceTcbTciType(t, multiTcbInfo, tciType) + // Check hash algorithm + checkDiceTcbHashAlgorithm(t, multiTcbInfo, hashAlg) + // Check cumulative value of derived TCi node + checkCurrentDiceTcbMeasurements(t, multiTcbInfo, seqLabel) + } + + if !simulation { + // Restore default handle for other tests + _, err := c.RotateContextHandle(&certifyKeyResp.Handle, TargetIsDefault) + if err != nil { + t.Errorf("Unable to rotate context to default handle %v", err) + } + } +} + // Ignores critical extensions that are unknown to x509 package // but atleast defined in DPE certificate profile specification. // UnhandledCriticalExtensions may have only custom extensions mentioned in spec -// unknownExtnMap collects extensions unknown to both x59 and the DICE certificate profiles spec. +// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec. // positive case expects the unknownExtnMap to be empty. func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) { t.Helper() @@ -156,6 +357,11 @@ func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) { } } +// Ignores extended key usages that are unknown to x509 package +// but atleast defined in DPE certificate profile specification. +// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec +// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec. +// positive case expects the unknownKeyUsagesMap to be empty. func removeTcgDiceExtendedKeyUsages(t *testing.T, certs []*x509.Certificate) { t.Helper() unknownKeyUsagesMap := map[string][]string{} @@ -218,7 +424,7 @@ func checkCertifyKeyTcgUeidExtension(t *testing.T, c *x509.Certificate, label [] // A tcg-dice-MultiTcbInfo extension. // This extension SHOULD be marked as critical. -func checkCertifyKeyMultiTcbInfoExtension(t *testing.T, c *x509.Certificate) (TcgMultiTcbInfo, error) { +func checkCertifyKeyMultiTcbInfoExtensionStructure(t *testing.T, c *x509.Certificate) (TcgMultiTcbInfo, error) { t.Helper() var multiTcbInfo TcgMultiTcbInfo var err error @@ -241,7 +447,88 @@ func checkCertifyKeyMultiTcbInfoExtension(t *testing.T, c *x509.Certificate) (Tc return multiTcbInfo, err } -// Check whether certificate extended key usage is as per spec +// Checks whether the VendorInfo is 4-bytes TARGET_LOCALITY parameter +func checkDiceTcbVendorInfo(t *testing.T, multiTcbInfo []DiceTcbInfo, targetLocality uint32) { + isMatchFound := false + vendorInfoBytes := make([]byte, 4) + binary.BigEndian.PutUint32(vendorInfoBytes, targetLocality) + for i, diceTcb := range multiTcbInfo { + if reflect.DeepEqual(diceTcb.VendorInfo, vendorInfoBytes) { + isMatchFound = true + } + + if !isMatchFound { + t.Errorf("[ERROR]: Dice TCB information block - %d does not have VendorInfo matching with the target locality parameter", i) + } + } +} + +// Checks whether INPUT_TYPE field in DeriveChild Request, a caller-supplied measurement type +// populates the "type" field in the DiceTcbInfo extension. +func checkCurrentDiceTcbTciType(t *testing.T, multiTcbInfo []DiceTcbInfo, expectedTciType uint32) { + currentNodeIndex := 0 + expectedTciTypeBytes := make([]byte, 4) + binary.BigEndian.PutUint32(expectedTciTypeBytes, expectedTciType) + if !reflect.DeepEqual(multiTcbInfo[currentNodeIndex].Type, expectedTciTypeBytes) { + t.Errorf("[ERROR]: Unexpected TCI type for current DICE TCB block, want %v but got %v", expectedTciTypeBytes, multiTcbInfo[0].Type) + } +} + +// Checks the FWID block's Digest. +// FWID at index 0 has the TCI_CURRENT as digest +// FWID at index 1 has the TCI_CUMULATIVE as digest +// The length of FWID array in each DICE TCB information block is 2. +func checkCurrentDiceTcbMeasurements(t *testing.T, multiTcbInfo []DiceTcbInfo, expectedCurrentValue []byte) { + currentNodeIndex := 0 + currentDiceTcb := multiTcbInfo[currentNodeIndex] + measurements := currentDiceTcb.Fwids + + currentTci := measurements[0].Digest + cumulativeTci := measurements[1].Digest + prevNodeCumulativeTci := multiTcbInfo[currentNodeIndex+1].Fwids[0].Digest + + if !bytes.Equal(currentTci, expectedCurrentValue) { + t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrentValue, currentTci) + } + + // Calculate expected cumulative value + var expectedCumulativeValue []byte + if measurements[1].HashAlg.Equal(OidSHA384) { + hasher := sha512.New384() + hasher.Write(prevNodeCumulativeTci) + hasher.Write(currentTci) + expectedCumulativeValue = hasher.Sum(nil) + } else if measurements[1].HashAlg.Equal(OidSHA256) { + hasher := sha256.New() + hasher.Write(prevNodeCumulativeTci) + hasher.Write(currentTci) + expectedCumulativeValue = hasher.Sum(nil) + } else { + t.Errorf("[ERROR]: Unsupported hash algorithm for generating TCI cumulative value.") + return + } + + // Verify the FWID index-1 which has TCI_CUMULATIVE value of current node + if !bytes.Equal(cumulativeTci, expectedCumulativeValue) { + t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulativeValue, cumulativeTci) + } +} + +// Checks whether the Hash Algorithm field in FWID block is correctly set as follows +// For measurements provided via DeriveChild, the hash algorithm is specified by the profile-specific certificate +// or CSR format which is SHA256 or SHA384 based on client type. +// For measurements provided during auto-initialization, the hash algorithm is implementation-defined +func checkDiceTcbHashAlgorithm(t *testing.T, multiTcbInfo []DiceTcbInfo, hashAlg asn1.ObjectIdentifier) { + for i, diceTcb := range multiTcbInfo { + for j, fwid := range diceTcb.Fwids { + if !fwid.HashAlg.Equal(hashAlg) { + t.Errorf("[ERROR]: Unexpected hash algorithm for FWID block-%d of DICE TCB block-%d, expected %s but got %s.", j, i, hashAlg, fwid.HashAlg) + } + } + } +} + +// Checks whether certificate extended key usage is as per spec // OID for ExtendedKeyUsage Extension: 2.5.29.37 // The ExtendedKeyUsage extension SHOULD be marked as critical // If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca @@ -297,7 +584,7 @@ func checkCertifyKeyExtendedKeyUsages(t *testing.T, c *x509.Certificate) (*TcgMu return multiTcbInfo, err } -// Check for KeyUsage Extension as per spec +// Checks for KeyUsage Extension as per spec // If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign // If IsCA = false, KeyUsage extension MUST contain only DigitalSignature func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) { @@ -319,29 +606,29 @@ func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) { } -// Validate basic constraints in certificate returned by CertifyKey command +// Validates basic constraints in certificate returned by CertifyKey command // against the flag set for input parameter. // The BasicConstraints extension MUST be included // If CertifyKey AddIsCA is set, IsCA MUST be set to true. // If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false -func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags uint32) { +func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags CertifyKeyFlags) { t.Helper() flagsBuf := &bytes.Buffer{} binary.Write(flagsBuf, binary.LittleEndian, flags) - flagIsCA := uint32(CertifyAddIsCA)&flags != 0 + flagIsCA := CertifyAddIsCA&flags != 0 if flagIsCA != c.IsCA { t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, c.IsCA) } } -// Validate X509 fields in certificate returned by CertifyKey command. +// Validates X509 fields in certificate returned by CertifyKey command. func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags uint32, label []byte) { t.Helper() // Check for basic constraints extension - checkCertifyKeyBasicConstraints(t, c, flags) + checkCertifyKeyBasicConstraints(t, c, CertifyKeyFlags(flags)) // Check key usage extensions - DigitalSignature, CertSign checkCertifyKeyExtensions(t, c) @@ -354,9 +641,10 @@ func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags uint32, lab checkCertifyKeyTcgUeidExtension(t, c, label) // Check MultiTcbInfo Extension structure - checkCertifyKeyMultiTcbInfoExtension(t, c) + checkCertifyKeyMultiTcbInfoExtensionStructure(t, c) } +// Parses X509 certificate func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { t.Helper() failed := false @@ -431,81 +719,8 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate return x509Cert } -func testCertifyKey(d TestDPEInstance, client DPEClient, t *testing.T, use_simulation bool) { - var ctx ContextHandle - if use_simulation { - if d.GetSupport().Simulation { - handle, err := client.InitializeContext(InitIsSimulation) - if err != nil { - t.Fatal("The instance should be able to create a simulation context.") - } - // Could prove difficult to prove it is a cryptographically secure random. - if *handle == ContextHandle([16]byte{0}) { - t.Fatal("Incorrect simulation context handle.") - } - - defer client.DestroyContext(handle, 0) - } else { - t.Errorf("[ERROR]: DPE instance doesn't support simulation contexts.") - } - } else { - //default context - ctx = [16]byte{0} - } - - type Params struct { - Label []byte - Flags CertifyKeyFlags - } - - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - seqLabel := make([]byte, digestLen) - for i, _ := range seqLabel { - seqLabel[i] = byte(i) - } - - certifyKeyParams := []Params{ - Params{Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, - Params{Label: seqLabel, Flags: CertifyKeyFlags(0)}, - } - - for _, params := range certifyKeyParams { - // Get DPE leaf certificate from CertifyKey - certifyKeyResp, err := client.CertifyKey(&ctx, params.Label, CertifyKeyX509, params.Flags) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) - } - - // Get root and intermediate certificates to validate certificate chain of leaf cert - certChainBytes, err := client.GetCertificateChain() - if err != nil { - t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) - } - - leafCertBytes := certifyKeyResp.Certificate - - // Run X.509 linter on full certificate chain and file issues for errors - leafCert := checkCertificateStructure(t, leafCertBytes) - certChain := checkCertificateChain(t, certChainBytes) - - // Validate that all X.509 fields conform with the format defined in the DPE iRoT profile - validateCertifyKeyCert(t, leafCert, uint32(params.Flags), params.Label) - - // Ensure full certificate chain has valid signatures - // This also checks certificate lifetime, signatures as part of cert chain validation - validateLeafCertChain(t, certChain, leafCert) - - // TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again. - } -} - -// Build certificate chain and calls to validateSignature on each chain. -func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { +// Builds certificate chain and calls to validateSignature on each chain. +func checkLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { t.Helper() certsToProcess := []*x509.Certificate{leafCert} @@ -531,6 +746,7 @@ func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert } } +// Builds Certificate chain verifier parameters. func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions { roots := x509.NewCertPool() intermediates := x509.NewCertPool() @@ -555,11 +771,7 @@ func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.Verify return opts } -func extractFlagBit(pos int, flags uint32) bool { - var mask uint32 = (1 << pos) - return (flags & mask) > 0 -} - +// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. func getKeyUsageNames(keyUsage x509.KeyUsage) []string { keyUsageNames := []string{} @@ -601,3 +813,46 @@ func getKeyUsageNames(keyUsage x509.KeyUsage) []string { return keyUsageNames } + +// Checks CertifyKey command response against public key extracted from certificate returned in response +func checkCertifyKeyResponse(t *testing.T, x509Cert *x509.Certificate, response CertifiedKey, hashAlg asn1.ObjectIdentifier) { + var err error + + publicKeyDer, err := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) + if err != nil { + t.Fatalf("[FATAL]: Could not marshal pub key: %v", err) + } + + // Parse the DER-encoded public key + pubKey, err := x509.ParsePKIXPublicKey(publicKeyDer) + if err != nil { + t.Fatalf("[FATAL]: Failed to parse DER-encoded public key: %v", err) + } + + if _, ok := pubKey.(*ecdsa.PublicKey); !ok { + t.Fatal("[FATAL]: Public key is not a ecdsa key") + } + + var pubKeyInResponse ecdsa.PublicKey + + if hashAlg.Equal(OidSHA384) { + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P384(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + } else if hashAlg.Equal(OidSHA256) { + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + } else { + t.Errorf("[ERROR]: Unsupported hash algorithm.") + return + } + + if !(pubKeyInResponse.Equal(pubKey)) { + t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the leaf certificate.") + } +} diff --git a/verification/client.go b/verification/client.go index e4e4a060..9f5f2305 100755 --- a/verification/client.go +++ b/verification/client.go @@ -42,11 +42,13 @@ type DPESignedHash struct { type DPEClient interface { InitializeContext(flags InitCtxFlags) (*ContextHandle, error) GetProfile() (*GetProfileResp, error) + DeriveChild(handle *ContextHandle, inputData []byte, flags DeriveChildFlags, tciType uint32, targetLocality uint32) (*DeriveChildResp, error) CertifyKey(handle *ContextHandle, label []byte, format CertifyKeyFormat, flags CertifyKeyFlags) (*CertifiedKey, error) GetCertificateChain() ([]byte, error) TagTCI(handle *ContextHandle, tag TCITag) (*ContextHandle, error) GetTaggedTCI(tag TCITag) (*DPETCI, error) DestroyContext(handle *ContextHandle, flags DestroyCtxFlags) error + RotateContextHandle(handle *ContextHandle, flags RotateContextHandleFlags) (*ContextHandle, error) Sign(handle *ContextHandle, label []byte, flags SignFlags, toBeSigned []byte) (*DPESignedHash, error) } diff --git a/verification/deriveChild.go b/verification/deriveChild.go new file mode 100644 index 00000000..b2c3e9be --- /dev/null +++ b/verification/deriveChild.go @@ -0,0 +1,274 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "errors" + "testing" +) + +var existingTciNodeCount = 0 + +func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { + // A tci node is already created at time of auto-initialization + existingTciNodeCount += 1 + testDeriveChild(d, c, t) +} + +func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { + handle := &DefaultContextHandle + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + + // Test wrong locality + + testDeriveChildWrongLocality(t, d, c, handle, digestLen) + + // Test child handles when MakeDefault flag is enabled/disabled + testChildHandles(t, d, c, handle, digestLen) + + // Test enabling MakeDefault flag + testMakeDefault(t, d, c, handle, digestLen) + + // Test child handle creation in other locality. + testMakeDefaultInNonDefaultContext(t, d, c, handle, digestLen) + + // Test Privilege escalation + testPrivilegeEscalation(t, d, c, handle, digestLen) + + // Test for error while retaining parent handle in default context + testRetainParentInDefaultContext(t, d, c, handle, digestLen) + + // Test retention of parent handle in non default context + testRetainParentInNonDefaultContext(t, d, c, handle, digestLen) + + // Test enabling MakeDefault and RetainParent flags + testRetainParentAndMakeDefault(t, d, c, handle, digestLen) + + // Test derive child contexts count limited by MAX_TCI_NODES supported by the profile + testMaxTcis(t, d, c, handle, digestLen) +} + +// Checks whether caller from one locality is prevented from making DPE calls to other locality +func testDeriveChildWrongLocality(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + + var err error + + // Modify locality of DPE instance to test + d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) + + // Restore locality of DPE instance after the test + defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + _, err = c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(MakeDefault), + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusInvalidLocality) + } else if !errors.Is(err, StatusInvalidLocality) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidLocality, err) + } +} + +// Check handle of default and non-default child +func testChildHandles(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + // MakeDefault flag is not set + r, err := c.DeriveChild(handle, + make([]byte, digestLen), + ChangeLocality, + 0, + DPE_SIMULATOR_OTHER_LOCALITY) + + if err != nil { + t.Fatalf("[FATAL]: Error while creating non-default child context handle: %s", err) + } + + if r.NewContextHandle == DefaultContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return random handle, but returned %q", &DefaultContextHandle) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 + + // MakeDefault flag is set + d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) + defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + r, err = c.DeriveChild(&r.NewContextHandle, + make([]byte, digestLen), + MakeDefault|ChangeLocality, + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY, + ) + + if err != nil { + t.Fatalf("[FATAL]: Error while creating default child context: %s", err) + } + + if r.NewContextHandle != DefaultContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return %q, but returned %q", DefaultContextHandle, r.NewContextHandle) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 +} + +// Checks whether the new context handle could be made the default handle by +// setting MakeDefault flag in default context. +func testMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + resp, err := c.DeriveChild(handle, + make([]byte, digestLen), + MakeDefault, + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY) + if err != nil { + t.Fatalf("[FATAL]: Error while setting child handle as default: %s", err) + } + + if resp.NewContextHandle != DefaultContextHandle { + t.Errorf("[FATAL]: The child handle is not set as default handle despite enabling MakeDefault flag: %s", err) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 +} + +// Checks default child handle creation in other locality. +func testMakeDefaultInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + + r, err := c.DeriveChild(handle, + make([]byte, digestLen), + MakeDefault|ChangeLocality, + 0, + DPE_SIMULATOR_OTHER_LOCALITY) + + if err != nil { + t.Fatalf("[FATAL]: Error while creating default child handle in non-default context: %s", err) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 + + // Revert hardware locality and handle for further tests + d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) + defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + _, err = c.DeriveChild(&r.NewContextHandle, + make([]byte, digestLen), + MakeDefault|ChangeLocality, + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY) + + if err != nil { + t.Fatalf("[FATAL]: Error while creating default child handle in default context: %s", err) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 +} + +// Checks whether the derived context does not escalate beyond the privileges of parent context. +func testPrivilegeEscalation(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + var err error + escalatedChildPrivileges := []DeriveChildFlags{InputAllowCA, InputAllowX509} + + for _, flag := range escalatedChildPrivileges { + _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|flag, 0, 0) + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusArgumentNotSupported) + } else if !errors.Is(err, StatusArgumentNotSupported) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusArgumentNotSupported, err) + } + } +} + +// Checks whether default context does not retain parent handle. +// This is because mixture of default and non-default handles are not allowed in this context. +// Parent handle is invalidated in default context. +func testRetainParentInDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + _, err := c.DeriveChild(handle, + make([]byte, digestLen), + RetainParent, + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY) + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } +} + +// Checks whether parent handle could be retained in a locality with non-default context. +func testRetainParentInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + _, err := c.DeriveChild(handle, + make([]byte, digestLen), + RetainParent|ChangeLocality, + 0, + DPE_SIMULATOR_OTHER_LOCALITY) + if err != nil { + t.Fatalf("[FATAL]: Error while retaining parent handle in non-default context: %s", err) + } + + // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. + existingTciNodeCount += 1 +} + +// Checks whether error is returned when RetainParent and MakeDefault flags are used together in presence of +// default context handle. This should fail because RetainParent flag and MakeDefault when used together +// tries to create two default context handles in the locality which is not allowed since a locality can have +// only one default context handle. +func testRetainParentAndMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + _, err := c.DeriveChild(handle, + make([]byte, digestLen), + RetainParent|ChangeLocality|MakeDefault, + 0, + DPE_SIMULATOR_OTHER_LOCALITY) + if err == nil { + t.Fatalf("[FATAL]: Error while retaining parent handle and making it default in non-default context: %s", err) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } +} + +// Checks whether the number of derived contexts (TCI nodes) are limited by MAX_TCI_NODES attribute of the profile +func testMaxTcis(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + + maxTciCount := d.GetMaxTciNodes() + allowedTciNodes := int(maxTciCount) - existingTciNodeCount + + for i := 0; i < allowedTciNodes; i++ { + resp, err := c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(MakeDefault), + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY, + ) + + if err != nil { + t.Fatalf("[FATAL]: Error encountered in executing derive child: %v", err) + } + handle = &resp.NewContextHandle + } + + // Exceed the Max TCI node count limit + _, err := c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(MakeDefault), + 0, + DPE_SIMULATOR_AUTO_INIT_LOCALITY, + ) + + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusMaxTCIs) + } else if !errors.Is(err, StatusMaxTCIs) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusMaxTCIs, err) + } +} diff --git a/verification/initializeContext.go b/verification/initializeContext.go index 68edbda4..764cc5ed 100644 --- a/verification/initializeContext.go +++ b/verification/initializeContext.go @@ -67,3 +67,28 @@ func testInitContext(d TestDPEInstance, client DPEClient, t *testing.T, simulati } } } + +func getContextHandle(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) *ContextHandle { + var handle *ContextHandle + var err error + if simulation { + if d.GetSupport().Simulation { + handle, err = c.InitializeContext(InitIsSimulation) + if err != nil { + t.Fatal("The instance should be able to create a simulation context.") + } + // Could prove difficult to prove it is a cryptographically secure random. + if *handle == ContextHandle([16]byte{0}) { + t.Fatal("Incorrect simulation context handle.") + } + } else { + t.Fatal("[FATAL]: DPE instance doesn't support simulation contexts.") + } + } else { + //default context + defaultContext := ContextHandle{0} + handle = &defaultContext + } + + return handle +} diff --git a/verification/simulator.go b/verification/simulator.go index 97ac04c5..6f57c219 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -230,9 +230,14 @@ func GetSimulatorTargets() []TestTarget { }, { "DefaultSupport", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "IsCA", "Tagging"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "IsCA", "Tagging", "RotateContext", "ExtendTci"}), AllTestCases, }, + { + "DeriveChildSupport", + getTestTarget([]string{"AutoInit", "InternalDice", "InternalInfo"}), + []TestCase{DeriveChildTestCase}, + }, { "GetProfile_Simulation", getTestTarget([]string{"Simulation"}), diff --git a/verification/verification.go b/verification/verification.go index ef5652db..6b0bb2f3 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -2,7 +2,9 @@ package verification -import "testing" +import ( + "testing" +) type DpeTestFunc func(d TestDPEInstance, c DPEClient, t *testing.T) @@ -27,9 +29,11 @@ var InitializeContextSimulationTestCase = TestCase{ var CertifyKeyTestCase = TestCase{ "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA"}, } + var CertifyKeySimulationTestCase = TestCase{ - "CertifyKeySimulation", TestCertifyKey_SimulationMode, []string{"AutoInit", "Simulation", "X509", "IsCA"}, + "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA"}, } + var GetCertificateChainTestCase = TestCase{ "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, } @@ -44,15 +48,19 @@ var TpmPolicySigningTestCase = TestCase{ "TPMPolicySigning", TestTpmPolicySigning, []string{"AutoInit", "X509"}, } +var DeriveChildTestCase = TestCase{ + "AutoInit", TestDeriveChild, []string{"AutoInit", "InternalDice", "InternalInfo"}, +} + var AllTestCases = []TestCase{ CertifyKeyTestCase, - CertifyKeySimulationTestCase, GetCertificateChainTestCase, TpmPolicySigningTestCase, TagTCITestCase, GetProfileTestCase, InitializeContextTestCase, InitializeContextSimulationTestCase, + CertifyKeySimulationTestCase, } func RunTargetTestCases(target TestTarget, t *testing.T) { From 12380d0333c904e40c626684a090b69c24468820 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Thu, 2 Nov 2023 19:27:35 +0530 Subject: [PATCH 04/17] deriveChild commit with a bug fix --- verification/Makefile | 42 ------ verification/README.md | 90 +------------ verification/tpm.go | 251 ----------------------------------- verification/verification.go | 5 - 4 files changed, 2 insertions(+), 386 deletions(-) delete mode 100644 verification/Makefile delete mode 100644 verification/tpm.go diff --git a/verification/Makefile b/verification/Makefile deleted file mode 100644 index 78b7940a..00000000 --- a/verification/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# Makefile to install and configure tpm emulator to run Go test verifying Caliptra DPE commands with TPM policy Signing - -SHELL := /bin/bash -SETUP_TPM_EMU_PATH := "/tmp/setup_tpm_emulator" -# Install tpm emulator dependencies -install_dependencies: - sudo apt-get update && \ - sudo apt-get install dh-autoreconf libssl-dev \ - libtasn1-6-dev pkg-config libtpms-dev \ - net-tools iproute2 libjson-glib-dev \ - tar\ - wget\ - git\ - build-essential\ - linux-generic\ - libgnutls28-dev expect gawk socat \ - libseccomp-dev make -y - -# Build and install tpm emulator -run_autogen_and_install: - sudo rm -rf $(SETUP_TPM_EMU_PATH) - mkdir $(SETUP_TPM_EMU_PATH) && cd $(SETUP_TPM_EMU_PATH); \ - git clone https://github.com/stefanberger/swtpm.git; \ - cd swtpm; \ - ./autogen.sh --with-openssl --prefix=/usr; \ - make -j4; \ - make -j4 check; \ - sudo make install - -# Install tpm2-tss -install_tpm2_tss: - sudo apt-get install libjson-c-dev libssl-dev libcurl4-gnutls-dev -y - cd $(SETUP_TPM_EMU_PATH); \ - wget https://github.com/tpm2-software/tpm2-tss/releases/download/3.1.0/tpm2-tss-3.1.0.tar.gz; \ - tar -xzvf tpm2-tss-3.1.0.tar.gz && cd tpm2-tss-3.1.0/ && ./configure && sudo make install && sudo ldconfig - -# Install tpm2-tools -install_tpm2_tools: - sudo apt-get install tpm2-tools - -# The 'setup_tpm_emulator' target runs all steps in order -setup_tpm_emulator: install_dependencies run_autogen_and_install install_tpm2_tss install_tpm2_tools diff --git a/verification/README.md b/verification/README.md index 5be607c6..45200d83 100644 --- a/verification/README.md +++ b/verification/README.md @@ -1,90 +1,4 @@ # DPE Verification Tests -This test suite is a userspace test-suite which exercises DPE commands end-to-end and ensures compliance with the DPE iRoT Profile. - -## Requirements -* Ubuntu 20 LTS and above -* Golang >= 1.20 -* Make -* Rustup, RustC >= 1.70 - -## Setting up Caliptra DPE Simulator -```sh -git clone https://github.com/chipsalliance/caliptra-dpe.git -cd caliptra-dpe/simulator/ -cargo build -cd ../verification -go test . -``` - -## Setting up TPM emulator -The Software TPM (emulator) is required to run a specific test that verifies Caliptra DPE flow with TPM emulator. -User may choose to configure test requirements either by using Makefile or through command line. - -### Setting up using Makefile -Users may use the target `setup_tpm_emulator` to install and configure TPM emulator. -```sh -# Navigate to verification folder if it is not the current directory -sudo make setup_tpm_emulator -``` -### Setting up using command line -Users may use command line instead of Makefile to install and configure TPM emulator. -If already configured using Makefile, this section shall be skipped and continue with section giving the steps to run the emulator. - -#### Install dependencies -Install the dependencies for software TPM installation. -```sh -sudo apt-get update && \ -sudo apt-get install dh-autoreconf libssl-dev \ - libtasn1-6-dev pkg-config libtpms-dev \ - net-tools iproute2 libjson-glib-dev \ - tar\ - wget\ - git\ - build-essential\ - linux-generic\ - libgnutls28-dev expect gawk socat \ - libseccomp-dev make -y -``` -#### Build TPM emulator -Run autogen.sh, make, check, and install -```sh -export SETUP_TPM_EMU_PATH="/tmp/setup_tpm_emulator" -sudo rm -rf ${SETUP_TPM_EMU_PATH} -mkdir ${SETUP_TPM_EMU_PATH} && cd ${SETUP_TPM_EMU_PATH} -git clone https://github.com/stefanberger/swtpm.git -cd ${SETUP_TPM_EMU_PATH}/swtpm -./autogen.sh --with-openssl --prefix=/usr -make -j4 -make -j4 check -sudo make install -``` -#### Install TPM tools -- Install_tpm2_tss -```sh -sudo apt-get install libjson-c-dev libssl-dev libcurl4-gnutls-dev -y -cd ${SETUP_TPM_EMU_PATH} -wget https://github.com/tpm2-software/tpm2-tss/releases/download/3.1.0/tpm2-tss-3.1.0.tar.gz -tar -xzvf tpm2-tss-3.1.0.tar.gz && cd tpm2-tss-3.1.0/ && ./configure && sudo make install && sudo ldconfig -``` -- Install tpm2-tools -```sh -sudo apt-get install tpm2-tools -``` -### Run TPM emulator -- To run the Go test to verify TPM Policy Signing, start the TPM emulator. -- Open separate terminal instance and issue commands to start. -- When started properly it displays the path of TPM device file. -- Mostly, TPM device path is /dev/tpm0 -```sh -mkdir -p /tmp/myvtpm -sudo modprobe tpm_vtpm_proxy -sudo swtpm chardev --vtpm-proxy --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 -``` -### Run TPM policy signing test -- Open another instance of terminal. -- Run the go test. -```sh -cd caliptra-dpe/verification -sudo go test . -v -tpm-policy-signing-validation="enabled" -tpm-path="/dev/tpm0" -``` +This test suite is a userspace test-suite which exercises DPE commands +end-to-end and ensures compliance with the DPE iRoT Profile. \ No newline at end of file diff --git a/verification/tpm.go b/verification/tpm.go deleted file mode 100644 index 761dd77a..00000000 --- a/verification/tpm.go +++ /dev/null @@ -1,251 +0,0 @@ -// Licensed under the Apache-2.0 license - -package verification - -import ( - "crypto/ecdsa" - "crypto/sha256" - "crypto/sha512" - "crypto/x509" - "encoding/binary" - "flag" - "io" - "math" - "math/big" - "strings" - "testing" - - "github.com/google/go-tpm-tools/client" - "github.com/google/go-tpm/legacy/tpm2" - "github.com/google/go-tpm/tpmutil" -) - -var ( - tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).") - tpmPolicySigningValidation = flag.String("tpm-policy-signing-validation", "disabled", "Validation of TPM policy signing with Caliptra DPE commands is enabled/disabled. By default, this is disabled.") - - handleNames = map[string][]tpm2.HandleType{ - "all": {tpm2.HandleTypeLoadedSession, tpm2.HandleTypeSavedSession, tpm2.HandleTypeTransient}, - "loaded": {tpm2.HandleTypeLoadedSession}, - "saved": {tpm2.HandleTypeSavedSession}, - "transient": {tpm2.HandleTypeTransient}, - } -) - -func TestTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { - if strings.ToLower(*tpmPolicySigningValidation) == "enabled" { - t.Log("Validation of TPM policy signing using Caliptra DPE commands is enabled.") - testTpmPolicySigning(d, c, t) - } else { - t.Log("Validation of TPM policy signing using Caliptra DPE commands is disabled, skipping this test.\n To enable this validation start the TPM emulator, set `go test . -tpm-policy-signing-validation=enabled` and rerun.") - return - } -} - -func flushAllContexts(t *testing.T, tpm io.ReadWriteCloser) { - totalHandles := 0 - for _, handleType := range handleNames["all"] { - handles, err := client.Handles(tpm, handleType) - if err != nil { - t.Fatalf("[FATAL]: Error getting handles %s: %v", *tpmPath, err) - } - for _, handle := range handles { - if err = tpm2.FlushContext(tpm, handle); err != nil { - t.Fatalf("[FATAL]: Error flushing handle 0x%x: %v", handle, err) - } - totalHandles++ - } - } -} - -func startTpmSession(t *testing.T, tpm io.ReadWriteCloser, alg tpm2.Algorithm) (tpmutil.Handle, []byte, error) { - - flushAllContexts(t, tpm) - sessHandle, nonce, err := tpm2.StartAuthSession(tpm, - tpm2.HandleNull, - tpm2.HandleNull, - make([]byte, 16), - nil, - tpm2.SessionPolicy, - tpm2.AlgNull, - alg) - - if err != nil { - t.Fatalf("[FATAL]: StartAuthSession() failed: %v", err) - } - - return sessHandle, nonce, nil -} - -func testTpmPolicySigning(d TestDPEInstance, c DPEClient, t *testing.T) { - var ctx ContextHandle = [16]byte{0} - var ec tpm2.EllipticCurve - var alg tpm2.Algorithm - - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - if digestLen == len(SHA256Digest{0}) { - alg = tpm2.AlgSHA256 - ec = tpm2.CurveNISTP256 - } else if digestLen == len(SHA384Digest{0}) { - alg = tpm2.AlgSHA384 - ec = tpm2.CurveNISTP384 - } - - //Create tpm auth session to get nonce and form label which is digest - tpm, err := tpm2.OpenTPM(*tpmPath) - if err != nil { - t.Fatalf("[FATAL]: Can't open TPM %s: %v", *tpmPath, err) - } - - sessHandle, nonce, err := startTpmSession(t, tpm, alg) - if err != nil { - t.Fatalf("[FATAL]: Error in getting tpm nonce") - } - - defer func() { - if err := tpm.Close(); err != nil { - t.Fatalf("[FATAL]: Can't close TPM %s: %v", *tpmPath, err) - } - }() - - defer tpm2.FlushContext(tpm, sessHandle) - - // Build SignHash request - expiry := int32(math.MinInt32) - digest := getDigest(nonce, expiry, digestLen) - - seqLabel := make([]byte, digestLen) - for i := range seqLabel { - seqLabel[i] = byte(i) - } - - // Get signed hash from DPE - signResp, err := c.Sign(&ctx, seqLabel, SignFlags(0), digest) - if err != nil { - t.Fatalf("[FATAL]: Could not sign: %v", err) - } - - certifyKeyResp, err := c.CertifyKey(&(signResp.Handle), seqLabel, CertifyKeyX509, CertifyKeyFlags(0)) - if err != nil { - t.Fatalf("[FATAL]: Could not CertifyKey: %v", err) - } - - pubKey := extractPubKey(t, certifyKeyResp.Certificate) - - // Get TPM handle loaded with public key - pkh := loadPubKey(t, pubKey, tpm, alg, ec) - - // Get encoded signature from TPM - r := new(big.Int).SetBytes(signResp.HmacOrSignatureR) - s := new(big.Int).SetBytes(signResp.SignatureS) - - encodedSignature := getEncodedSignature(t, r, s, alg) - - // Verify Policy with Signature - _, _, err = tpm2.PolicySigned(tpm, pkh, sessHandle, nonce, nil, nil, expiry, encodedSignature) - if err != nil { - t.Fatalf("[FATAL]: PolicySigned() failed: %v", err) - } - - t.Log("PolicySigning validation is successful") -} - -func getDigest(nonce []byte, expiry int32, digestLen int) []byte { - - expBytes := make([]byte, 4) - binary.BigEndian.PutUint32(expBytes, uint32(expiry)) - - toDigest := append(nonce, expBytes...) - - digest := make([]byte, digestLen) - if digestLen == len(SHA256Digest{0}) { - hash := sha256.Sum256(toDigest) - digest = hash[:] - } else if digestLen == len(SHA384Digest{0}) { - hash := sha512.Sum384(toDigest) - digest = hash[:] - } - return digest -} - -func extractPubKey(t *testing.T, leafBytes []byte) *ecdsa.PublicKey { - var x509Cert *x509.Certificate - var err error - - // Check whether certificate is DER encoded. - if x509Cert, err = x509.ParseCertificate(leafBytes); err != nil { - t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) - } - - publicKeyDer, err := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) - if err != nil { - t.Fatalf("[FATAL]: Could not marshal pub key: %v", err) - } - - // Parse the DER-encoded public key - pubKey, err := x509.ParsePKIXPublicKey(publicKeyDer) - if err != nil { - t.Fatalf("[FATAL]: Failed to parse DER-encoded public key: %v", err) - } - - if _, ok := pubKey.(*ecdsa.PublicKey); !ok { - t.Fatal("[FATAL]: Public key is not a ecdsa key") - } - - return pubKey.(*ecdsa.PublicKey) -} - -func loadPubKey(t *testing.T, pubKey any, tpm io.ReadWriteCloser, alg tpm2.Algorithm, ec tpm2.EllipticCurve) tpmutil.Handle { - var tpmPublic tpm2.Public - - // Create a tpm2.Public structure from the parsed ECDSA public key - switch pubKey := pubKey.(type) { - case *ecdsa.PublicKey: - tpmPublic = tpm2.Public{ - Type: tpm2.AlgECC, // ECDSA key type - NameAlg: alg, - Attributes: tpm2.FlagSign | tpm2.FlagSensitiveDataOrigin | tpm2.FlagUserWithAuth, - ECCParameters: &tpm2.ECCParams{ - Sign: &tpm2.SigScheme{ - Alg: tpm2.AlgECDSA, - Hash: alg, - }, - CurveID: ec, - Point: tpm2.ECPoint{ - XRaw: new(big.Int).SetBytes(pubKey.X.Bytes()).Bytes(), - YRaw: new(big.Int).SetBytes(pubKey.Y.Bytes()).Bytes(), - }, - }, - } - default: - t.Fatalf("[FATAL]: Unsupported public key type") - } - - pkh, _, err := tpm2.LoadExternal(tpm, tpmPublic, tpm2.Private{}, tpm2.HandleNull) - if err != nil { - t.Fatalf("[FATAL]: Unable to load eexternal public key. Error: %v", err) - } - - return pkh -} - -func getEncodedSignature(t *testing.T, r *big.Int, s *big.Int, alg tpm2.Algorithm) []byte { - signature := tpm2.Signature{ - Alg: tpm2.AlgECDSA, - ECC: &tpm2.SignatureECC{ - HashAlg: alg, - R: r, - S: s, - }, - } - encodedSign, err := signature.Encode() - if err != nil { - t.Fatalf("[FATAL]: Unable to encode signature: %v", err) - } - return encodedSign -} diff --git a/verification/verification.go b/verification/verification.go index 6b0bb2f3..826d7661 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -44,10 +44,6 @@ var GetProfileTestCase = TestCase{ "GetProfile", TestGetProfile, []string{}, } -var TpmPolicySigningTestCase = TestCase{ - "TPMPolicySigning", TestTpmPolicySigning, []string{"AutoInit", "X509"}, -} - var DeriveChildTestCase = TestCase{ "AutoInit", TestDeriveChild, []string{"AutoInit", "InternalDice", "InternalInfo"}, } @@ -55,7 +51,6 @@ var DeriveChildTestCase = TestCase{ var AllTestCases = []TestCase{ CertifyKeyTestCase, GetCertificateChainTestCase, - TpmPolicySigningTestCase, TagTCITestCase, GetProfileTestCase, InitializeContextTestCase, From 58b6d398e60f8a710b0b482a1692d3cd07069c54 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Thu, 2 Nov 2023 23:18:58 +0530 Subject: [PATCH 05/17] deriveChild commit with a bug fix --- verification/certifyKey.go | 15 +++++++++++++++ verification/go.mod | 11 +---------- verification/go.sum | 31 ++----------------------------- 3 files changed, 18 insertions(+), 39 deletions(-) diff --git a/verification/certifyKey.go b/verification/certifyKey.go index b14ed70f..cac17bca 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -194,6 +194,9 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo leafCert := checkCertificateStructure(t, leafCertBytes) certChain := checkCertificateChain(t, certChainBytes) + // Check default context handle is unchanged + testCertifyKeyRespHandle(*certifyKeyResp, t, handle) + // Check key returned in command response against certificate checkCertifyKeyResponse(t, leafCert, *certifyKeyResp, hashAlg) @@ -856,3 +859,15 @@ func checkCertifyKeyResponse(t *testing.T, x509Cert *x509.Certificate, response t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the leaf certificate.") } } + +// Checks whether the context handle is unchanged after sign command when default context handle is used. +func testCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) { + if *handle != DefaultContextHandle { + t.Logf("[LOG]: Handle is not default context, skipping check...") + return + } + + if res.Handle != *handle { + t.Errorf("[ERROR]: Handle must be unchanged by Signing, want original handle %v but got %v", handle, res.Handle) + } +} diff --git a/verification/go.mod b/verification/go.mod index 06f549c7..8224f8d3 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -3,25 +3,16 @@ module github.com/chipsalliance/caliptra-dpe/verification go 1.20 require ( - github.com/google/go-tpm v0.9.0 - github.com/google/go-tpm-tools v0.4.1 github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 github.com/zmap/zlint/v3 v3.4.1 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 ) require ( - github.com/google/go-sev-guest v0.7.0 // indirect - github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84 // indirect - github.com/google/logger v1.1.1 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/pborman/uuid v1.2.0 // indirect github.com/pelletier/go-toml v1.9.3 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/stretchr/testify v1.8.3 // indirect github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect golang.org/x/crypto v0.11.0 // indirect golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.11.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/verification/go.sum b/verification/go.sum index 08058358..674a22ee 100644 --- a/verification/go.sum +++ b/verification/go.sum @@ -6,30 +6,12 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= -github.com/google/go-attestation v0.5.0 h1:jXtAWT2sw2Yu8mYU0BC7FDidR+ngxFPSE+pl6IUu3/0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/go-sev-guest v0.7.0 h1:DBCABhTo7WicP27ZH/hwcCdjcmxFkxxMOQXm5hFcfp4= -github.com/google/go-sev-guest v0.7.0/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= -github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84 h1:XqVJa7fVU8b+Hlhcvw49qfg0+LYcRI+V+jYUrSek848= -github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84/go.mod h1:a8EIh1l5x7jmIrrOuH//xWn6y4Sk4yupwmMcJE006RI= -github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= -github.com/google/go-tpm-tools v0.4.1 h1:gYU6iwRo0tY3V6NDnS6m+XYog+b3g6YFhHQl3sYaUL4= -github.com/google/go-tpm-tools v0.4.1/go.mod h1:w03m0jynhTo7puXTYoyfpNOMqyQ9SB7sixnKWsS/1L0= -github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= -github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= -github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -39,12 +21,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -56,6 +34,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs= github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= @@ -71,7 +50,6 @@ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= github.com/zmap/zlint/v3 v3.4.1 h1:zhGB2Q1oPNS+bODC5tTPlKDOnLfDGyxejgAEp1SfFiQ= github.com/zmap/zlint/v3 v3.4.1/go.mod h1:WgepL2QqxyMHnrOWJ54NqrgfMtOyuXr52wEE0tcfo9k= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -110,15 +88,12 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -144,11 +119,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 0847e274c27c6fcb488f74d03c0b060a79596c9f Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 28 Nov 2023 21:55:08 +0530 Subject: [PATCH 06/17] rebase --- verification/abi.go | 4 +- verification/certifyKey.go | 969 ++++++++++++------------------------- verification/client.go | 1 - 3 files changed, 299 insertions(+), 675 deletions(-) diff --git a/verification/abi.go b/verification/abi.go index 18edc64c..fdaa0148 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -172,7 +172,7 @@ type CertifyKeyResp[CurveParameter Curve, Digest DigestAlgorithm] struct { type SignFlags uint32 const ( - IsSymmetric SignFlags = 1 << 31 // TODO: should be 30, a bug in rust side code. + IsSymmetric SignFlags = 1 << 30 ) type SignReq[Digest DigestAlgorithm] struct { @@ -452,7 +452,7 @@ func (c *dpeABI[_, Digest]) DeriveChildABI(cmd *DeriveChildReq[Digest]) (*Derive return &respStruct, err } -// DeriveChild calls DPE RotateContextABI command. +// RotateContext calls DPE RotateContextHandle command. func (c *dpeABI[_, Digest]) RotateContextABI(cmd *RotateContextHandleCmd) (*RotatedContextHandle, error) { var respStruct RotatedContextHandle diff --git a/verification/certifyKey.go b/verification/certifyKey.go index 6238a08e..2e031412 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -8,138 +8,81 @@ import ( "crypto/elliptic" "crypto/x509" "encoding/asn1" - "encoding/binary" "encoding/pem" - "errors" "fmt" "math/big" - "reflect" "testing" - "time" zx509 "github.com/zmap/zcrypto/x509" zlint "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" - - "golang.org/x/exp/slices" -) - -// This file is used to test the certify key command. -var ( - OidExtensionAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35} - OidExtensionBasicConstraints = asn1.ObjectIdentifier{2, 5, 29, 19} - OidExtensionExtKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 37} - OidExtensionTcgDiceUeid = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 4} - OidExtensionTcgDiceMultiTcbInfo = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 5} - OidExtensionTcgDiceKpIdentityInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 6} - OidExtensionTcgDiceKpIdentityLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 7} - OidExtensionTcgDiceKpAttestInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 8} - OidExtensionTcgDiceKpAttestLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 9} - OidExtensionTcgDiceKpAssertInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 10} - OidExtensionTcgDiceKpAssertLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 11} - OidExtensionTcgDiceKpEca = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 12} - OidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} - OidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} ) -var TcgDiceCriticalExtensions = [...]string{ - OidExtensionTcgDiceMultiTcbInfo.String(), - OidExtensionTcgDiceUeid.String(), +type CertifyKeyParams struct { + Label []byte + Flags CertifyKeyFlags } -var TcgDiceExtendedKeyUsages = [...]string{ - OidExtensionTcgDiceKpIdentityLoc.String(), - OidExtensionTcgDiceKpAttestLoc.String(), +func TestCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T) { + testCertifyKey(d, c, t, false) } -// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} -// -// TcgUeid ::== SEQUENCE { -// ueid OCTET STRING -// } -type TcgUeidExtension struct { - Ueid []uint8 `asn1:"ueid,implicit"` +func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + testCertifyKey(d, c, t, true) } -// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} -// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo -// -// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} -// -// DiceTcbInfo ::== SEQUENCE { -// vendor [0] IMPLICIT UTF8String OPTIONAL, -// model [1] IMPLICIT UTF8String OPTIONAL, -// version [2] IMPLICIT UTF8String OPTIONAL, -// svn [3] IMPLICIT INTEGER OPTIONAL, -// layer [4] IMPLICIT INTEGER OPTIONAL, -// index [5] IMPLICIT INTEGER OPTIONAL, -// fwids [6] IMPLICIT FWIDLIST OPTIONAL, -// flags [7] IMPLICIT OperationalFlags OPTIONAL, -// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, -// type [9] IMPLICIT OCTET STRING OPTIONAL, -// } -// -// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID -// FWID ::== SEQUENCE { -// hashAlg OBJECT IDENTIFIER, -// digest OCTET STRING -// } -// -// OperationalFlags ::= BIT STRING { -// notConfigured (0), -// notSecure (1), -// recovery (2), -// debug (3) -// } - -type Fwid struct { - HashAlg asn1.ObjectIdentifier - Digest []byte -} +// Checks whether FWID array omits index-1 when extend TCI is not supported in DPE profile. +func TestCertifyKeyWithoutExtendTciSupport(d TestDPEInstance, c DPEClient, t *testing.T) { + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) -type DiceTcbInfo struct { - Vendor string `asn1:"optional,tag:0,utf8"` - Model string `asn1:"optional,tag:1,utf8"` - Version string `asn1:"optional,tag:2,utf8"` - SVN int `asn1:"optional,tag:3"` - Layer int `asn1:"optional,tag:4"` - Index int `asn1:"optional,tag:5"` - Fwids []Fwid `asn1:"optional,tag:6"` - Flags OperationalFlag `asn1:"optional,tag:7"` - VendorInfo []byte `asn1:"optional,tag:8"` - Type []byte `asn1:"optional,tag:9"` -} + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + digestLen := profile.GetDigestSize() -type OperationalFlag int + // Get DPE leaf certificate from CertifyKey + certifiedKey, err := c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyKeyFlags(0)) + if err != nil { + t.Fatalf("[FATAL]: Could not certify key: %v", err) + } -const ( - NotConfigured OperationalFlag = iota - NotSecure - Debug - Recovery -) + leafCertBytes := certifiedKey.Certificate + var leafCert *x509.Certificate -type TcgMultiTcbInfo = []DiceTcbInfo + if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { + t.Errorf("[ERROR]: Could not parse leaf certificate %s", err) + } -type CertifyKeyParams struct { - Label []byte - Flags CertifyKeyFlags -} + multiTcbInfo, err := getMultiTcbInfo(leafCert) + if err != nil { + t.Errorf("[ERROR]: Could not parse multi TCB information: extension %s", err) + } -func TestCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T) { - testCertifyKey(d, c, t, false) -} + if len(multiTcbInfo) == 0 { + t.Errorf("[ERROR]: Certificate MutliTcbInfo is empty") + } -func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { - testCertifyKey(d, c, t, true) + // Check whether fwids array has only fwids[0] i.e, TCI_CURRENT measurement + // and TCI_CUMULATIVE i.e fwids[1] is omitted in every Dice TCB info block + for i, tcbinfo := range multiTcbInfo { + if len(tcbinfo.Fwids) != 1 { + t.Errorf("Extend TCI is not supported by profile, expected FWIDs length in block-%d is %d but got %d", i, 1, len(tcbinfo.Fwids)) + } + } } func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { - handle := getContextHandle(d, c, t, simulation) - targetLocality := DPE_SIMULATOR_AUTO_INIT_LOCALITY + handle := getInitialContextHandle(d, c, t, simulation) if simulation { - targetLocality = DPE_SIMULATOR_OTHER_LOCALITY - defer c.DestroyContext(handle, 0) + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() } profile, err := GetTransportProfile(d) @@ -148,18 +91,11 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo } digestLen := profile.GetDigestSize() - // Test wrong locality for autoinitialized context - if !simulation { - testWrongLocalityForCertifyKey(d, c, t, handle) - } - var hashAlg asn1.ObjectIdentifier if digestLen == 32 { hashAlg = OidSHA256 } else if digestLen == 48 { hashAlg = OidSHA384 - } else { - t.Fatal("Unknown Hash Algorithm") } seqLabel := make([]byte, digestLen) @@ -169,11 +105,11 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo certifyKeyParams := []CertifyKeyParams{ {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, + {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(CertifyAddIsCA)}, {Label: seqLabel, Flags: CertifyKeyFlags(0)}, } for _, params := range certifyKeyParams { - // Get DPE leaf certificate from CertifyKey certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) if err != nil { @@ -193,519 +129,184 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo certChain := checkCertificateChain(t, certChainBytes) // Check default context handle is unchanged - testCertifyKeyRespHandle(*certifyKeyResp, t, handle) + checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) // Check key returned in command response against certificate checkCertifyKeyResponse(t, leafCert, *certifyKeyResp, hashAlg) + // Ensure full certificate chain has valid signatures + // This also checks certificate lifetime, signatures as part of cert chain validation + if err = validateLeafCertChain(certChain, leafCert); err != nil { + t.Errorf("[ERROR]: %v", err) + } + // Check for basic constraints extension - checkCertifyKeyBasicConstraints(t, leafCert, params.Flags) + if err = checkBasicConstraints(leafCert, params.Flags); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Check key usage extensions - DigitalSignature, CertSign - checkCertifyKeyExtensions(t, leafCert) + if err = checkKeyExtensions(leafCert); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Check extended key usage extensions - checkCertifyKeyExtendedKeyUsages(t, leafCert) + if err = checkExtendedKeyUsages(leafCert); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Check critical UEID and Multi Tcb Info TCG extensions // Check UEID extension - checkCertifyKeyTcgUeidExtension(t, leafCert, params.Label) + if err = checkTcgUeidExtension(leafCert, params.Label); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Check MultiTcbInfo Extension structure - multiTcbInfo, err := checkCertifyKeyMultiTcbInfoExtensionStructure(t, leafCert) - if err != nil { - t.Errorf("Error while unmarshalling MultiTCB information %v, skipping MultiTCB validation", err) - } else { - // Check type field - checkCurrentDiceTcbTciType(t, multiTcbInfo, 0) - // Check vendorInfo field - checkDiceTcbVendorInfo(t, multiTcbInfo, targetLocality) - // Check hash algorithm - checkDiceTcbHashAlgorithm(t, multiTcbInfo, hashAlg) + if _, err = getMultiTcbInfo(leafCert); err != nil { + t.Errorf("[ERROR]: %v", err) } - // Ensure full certificate chain has valid signatures - // This also checks certificate lifetime, signatures as part of cert chain validation - checkLeafCertChain(t, certChain, leafCert) - - if simulation { - handle = &certifyKeyResp.Handle - } + // Reassign handle for simulation mode. + // However, this does not impact in default mode because + // same default context handle is returned in default mode. + handle = &certifyKeyResp.Handle } // DeriveChild to add more TCIs and call CertifyKey again. - checkWithDerivedChildContext(d, c, t, digestLen, hashAlg, handle, simulation) + if simulation { + handle = checkWithDerivedChildContextSimulation(d, c, t, handle) + } else { + checkWithDerivedChildContext(d, c, t, handle) + } } -// Checks whether error is reported when caller from one locality uses another locality -func testWrongLocalityForCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) { - var err error - - // Modify locality of DPE instance to test - d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) - - // Restore locality of DPE instance after the test - defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) - - // Get digest size +// Checks Multi Tcb Info for context derived from non-simulation mode +// Check CertifyKey command after adding more TCIs by DeriveChild command. +// The MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. +// In a DiceTcbInfo block of a given TCI node, +// - the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. +// - the "fwid" field must contain cumulative TCI measurement. +func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) { profile, err := GetTransportProfile(d) if err != nil { t.Fatalf("Could not get profile: %v", err) } - digestLen := profile.GetDigestSize() - _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyKeyFlags(0)) - if err == nil { - t.Fatalf("[FATAL]: CertifyKey command should return %q, but returned no error", StatusInvalidLocality) - } else if !errors.Is(err, StatusInvalidLocality) { - t.Fatalf("[FATAL]: Incorrect error type. CertifyKey command should return %q, but returned %q", StatusInvalidLocality, err) - } -} -// Check CertifyKey command after adding more TCIs by DeriveChild command. -// The MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. -// In a DiceTcbInfo block of a given TCI node, -// the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. -// the "fwid" field must contain cumulative TCI measurement. -func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, digestLen int, hashAlg asn1.ObjectIdentifier, handle *ContextHandle, simulation bool) { - targetLocality := DPE_SIMULATOR_AUTO_INIT_LOCALITY - if simulation { - targetLocality = DPE_SIMULATOR_OTHER_LOCALITY + var hashAlg asn1.ObjectIdentifier + if digestLen == 32 { + hashAlg = OidSHA256 + } else if digestLen == 48 { + hashAlg = OidSHA384 } - seqLabel := make([]byte, digestLen) - for i := range seqLabel { - seqLabel[i] = byte(i) + childTCI1 := make([]byte, digestLen) + for i := range childTCI1 { + childTCI1[i] = byte(i + 1) } - tciType := uint32(1) - dc, err := c.DeriveChild(handle, - seqLabel, - InputAllowX509, - tciType, - DPE_SIMULATOR_AUTO_INIT_LOCALITY) + // Set tciType to verify in multiTcbInfo extension + tciType := uint32(2) + // Preserve parent context to restore for subsequent tests + parentHandle, err := c.RotateContextHandle(handle, RotateContextHandleFlags(0)) if err != nil { - t.Fatalf("[FATAL]: Derive child command failed with error: %v", err) + t.Errorf("[ERROR]: Error while rotating parent context handle, this may cause failure in subsequent tests: %s", err) } - // Get DPE leaf certificate from CertifyKey - certifyKeyResp, err := c.CertifyKey(&dc.NewContextHandle, - seqLabel, - CertifyKeyX509, - CertifyKeyFlags(0)) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key using derived child context handle: %v", err) - } - leafCertBytes := certifyKeyResp.Certificate - - // Run X.509 linter on full certificate chain and file issues for errors - leafCert := checkCertificateStructure(t, leafCertBytes) - - // Check MultiTcbInfo Extension structure - multiTcbInfo, err := checkCertifyKeyMultiTcbInfoExtensionStructure(t, leafCert) - if err != nil { - t.Errorf("Error while unmarshalling MultiTCB information %v, skipping MultiTCB validation", err) - } else { - // Check vendorInfo field - checkDiceTcbVendorInfo(t, multiTcbInfo, targetLocality) - // Check type field - checkCurrentDiceTcbTciType(t, multiTcbInfo, tciType) - // Check hash algorithm - checkDiceTcbHashAlgorithm(t, multiTcbInfo, hashAlg) - // Check cumulative value of derived TCi node - checkCurrentDiceTcbMeasurements(t, multiTcbInfo, seqLabel) - } - - if !simulation { - // Restore default handle for other tests - _, err := c.RotateContextHandle(&certifyKeyResp.Handle, TargetIsDefault) + // Deferred call to restore default context handle for subsequent tests + defer func() { + _, err = c.RotateContextHandle(parentHandle, RotateContextHandleFlags(TargetIsDefault)) if err != nil { - t.Errorf("Unable to rotate context to default handle %v", err) - } - } -} - -// Ignores critical extensions that are unknown to x509 package -// but atleast defined in DPE certificate profile specification. -// UnhandledCriticalExtensions may have only custom extensions mentioned in spec -// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec. -// positive case expects the unknownExtnMap to be empty. -func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) { - t.Helper() - unknownExtnMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnhandledCriticalExtensions) > 0 { - unknownExtns := []string{} - for _, extn := range cert.UnhandledCriticalExtensions { - if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { - unknownExtns = append(unknownExtns, extn.String()) - } - } - - if len(unknownExtnMap) == 0 { - cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} - } else { - unknownExtnMap[cert.Subject.String()] = unknownExtns - } - } - } - // The error details in this map will be logged - if len(unknownExtnMap) > 0 { - for certSubject, ext := range unknownExtnMap { - t.Errorf("[ERROR]: Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext) - } - t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unhandled critical extensions list") - } -} - -// Ignores extended key usages that are unknown to x509 package -// but atleast defined in DPE certificate profile specification. -// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec -// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec. -// positive case expects the unknownKeyUsagesMap to be empty. -func removeTcgDiceExtendedKeyUsages(t *testing.T, certs []*x509.Certificate) { - t.Helper() - unknownKeyUsagesMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnknownExtKeyUsage) > 0 { - unknownKeyUsages := []string{} - for _, eku := range cert.UnknownExtKeyUsage { - if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { - unknownKeyUsages = append(unknownKeyUsages, eku.String()) - } - } - - if len(unknownKeyUsagesMap) == 0 { - cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} - } else { - unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages - } - } - } - // The error details in this map will be logged - if len(unknownKeyUsagesMap) > 0 { - for certSubject, ext := range unknownKeyUsagesMap { - t.Errorf("[ERROR]: Certificate \"%s\" has unknown extended key usages \"%s\"", certSubject, ext) + t.Errorf("[ERROR]: Error while restoring parent context handle as default context handle, this may cause failure in subsequent tests: %s", err) } - t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unknown extended key usages list") - } -} - -// A tcg-dice-Ueid extension MUST be added -// This SHALL be populated by the LABEL input parameter to CertifyKey -// The extension SHOULD be marked as critical -func checkCertifyKeyTcgUeidExtension(t *testing.T, c *x509.Certificate, label []byte) { - t.Helper() - - isFound := false - // Check UEID extension - for _, ext := range c.Extensions { - if ext.Id.Equal(OidExtensionTcgDiceUeid) { - isFound = true - if !ext.Critical { - t.Errorf("[ERROR]: tcg-dice-Ueid extension is NOT marked as CRITICAL") - } - var ueid TcgUeidExtension = TcgUeidExtension{} - _, err := asn1.Unmarshal(ext.Value, &ueid) - if err != nil { - t.Errorf("[ERROR]: Error encountered while unmarshalling value of UEID extension, %s", err.Error()) - } - - if !reflect.DeepEqual(ueid.Ueid, label) { - // Ueid extn value doen not match the label - t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") - } - break - } - } - if !isFound { - t.Errorf("[ERROR]: tcg-dice-Ueid extension is missing") - } -} - -// Checks whether the VendorInfo is 4-bytes TARGET_LOCALITY parameter -func checkDiceTcbVendorInfo(t *testing.T, multiTcbInfo []DiceTcbInfo, targetLocality uint32) { - isMatchFound := false - vendorInfoBytes := make([]byte, 4) - binary.BigEndian.PutUint32(vendorInfoBytes, targetLocality) - for i, diceTcb := range multiTcbInfo { - if reflect.DeepEqual(diceTcb.VendorInfo, vendorInfoBytes) { - isMatchFound = true - } - - if !isMatchFound { - t.Errorf("[ERROR]: Dice TCB information block - %d does not have VendorInfo matching with the target locality parameter", i) - } - } -} - -// Checks whether INPUT_TYPE field in DeriveChild Request, a caller-supplied measurement type -// populates the "type" field in the DiceTcbInfo extension. -func checkCurrentDiceTcbTciType(t *testing.T, multiTcbInfo []DiceTcbInfo, expectedTciType uint32) { - currentNodeIndex := 0 - expectedTciTypeBytes := make([]byte, 4) - binary.BigEndian.PutUint32(expectedTciTypeBytes, expectedTciType) - if !reflect.DeepEqual(multiTcbInfo[currentNodeIndex].Type, expectedTciTypeBytes) { - t.Errorf("[ERROR]: Unexpected TCI type for current DICE TCB block, want %v but got %v", expectedTciTypeBytes, multiTcbInfo[0].Type) - } -} - -// Checks the FWID block's Digest. -// FWID at index 0 has the TCI_CURRENT as digest -// FWID at index 1 has the TCI_CUMULATIVE as digest -// The length of FWID array in each DICE TCB information block is 2. -func checkCurrentDiceTcbMeasurements(t *testing.T, multiTcbInfo []DiceTcbInfo, expectedCurrentValue []byte) { - currentNodeIndex := 0 - currentDiceTcb := multiTcbInfo[currentNodeIndex] - measurements := currentDiceTcb.Fwids - - currentTci := measurements[0].Digest - cumulativeTci := measurements[1].Digest - prevNodeCumulativeTci := multiTcbInfo[currentNodeIndex+1].Fwids[0].Digest - - if !bytes.Equal(currentTci, expectedCurrentValue) { - t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrentValue, currentTci) - } - - // Calculate expected cumulative value - var expectedCumulativeValue []byte - if measurements[1].HashAlg.Equal(OidSHA384) { - hasher := sha512.New384() - hasher.Write(prevNodeCumulativeTci) - hasher.Write(currentTci) - expectedCumulativeValue = hasher.Sum(nil) - } else if measurements[1].HashAlg.Equal(OidSHA256) { - hasher := sha256.New() - hasher.Write(prevNodeCumulativeTci) - hasher.Write(currentTci) - expectedCumulativeValue = hasher.Sum(nil) - } else { - t.Errorf("[ERROR]: Unsupported hash algorithm for generating TCI cumulative value.") - return - } + }() - // Verify the FWID index-1 which has TCI_CUMULATIVE value of current node - if !bytes.Equal(cumulativeTci, expectedCumulativeValue) { - t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulativeValue, cumulativeTci) - } -} + // Derive Child context with input data, tag it and check TCI_CUMULATIVE + childCtx, err := c.DeriveChild(parentHandle, + childTCI1, + DeriveChildFlags(InputAllowX509|RetainParent), + tciType, + 0) -// Checks whether the Hash Algorithm field in FWID block is correctly set as follows -// For measurements provided via DeriveChild, the hash algorithm is specified by the profile-specific certificate -// or CSR format which is SHA256 or SHA384 based on client type. -// For measurements provided during auto-initialization, the hash algorithm is implementation-defined -func checkDiceTcbHashAlgorithm(t *testing.T, multiTcbInfo []DiceTcbInfo, hashAlg asn1.ObjectIdentifier) { - for i, diceTcb := range multiTcbInfo { - for j, fwid := range diceTcb.Fwids { - if !fwid.HashAlg.Equal(hashAlg) { - t.Errorf("[ERROR]: Unexpected hash algorithm for FWID block-%d of DICE TCB block-%d, expected %s but got %s.", j, i, hashAlg, fwid.HashAlg) - } - } + if err != nil { + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } -} - -// Checks whether certificate extended key usage is as per spec -// OID for ExtendedKeyUsage Extension: 2.5.29.37 -// The ExtendedKeyUsage extension SHOULD be marked as critical -// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca -// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc -func checkCertifyKeyExtendedKeyUsages(t *testing.T, c *x509.Certificate) (*TcgMultiTcbInfo, error) { - t.Helper() - var multiTcbInfo *TcgMultiTcbInfo - var err error - - extKeyUsage := []asn1.ObjectIdentifier{} - for _, ext := range c.Extensions { - if ext.Id.Equal(OidExtensionExtKeyUsage) { // OID for ExtKeyUsage extension - // Extract the OID value from the extension - _, err := asn1.Unmarshal(ext.Value, &extKeyUsage) - if err != nil { - t.Errorf("[ERROR]: Failed to unmarshal the Extended Key Usage extension: %v", err) - continue - } + childHandle := &childCtx.NewContextHandle + parentHandle = &childCtx.ParentContextHandle - if !ext.Critical { - t.Errorf("[ERROR]: The Extended Key Usage extension IS NOT CRITICAL, MUST BE CRITICAL") - } - break + // Clean up contexts + defer func() { + err := c.DestroyContext(childHandle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) } - } + }() - if len(extKeyUsage) == 0 { - t.Errorf("[ERROR]: The Extended Key Usage extension is empty") + var childTcbInfo DiceTcbInfo + childHandle, childTcbInfo, err = getTcbInfoForHandle(c, childHandle) + if err != nil { + t.Fatalf("[FATAL]: Could not get TcbInfo: %v", err) } - // Iterate over the OIDs in the ExtKeyUsage extension - isExtendedKeyUsageValid := false - var expectedKeyUsage asn1.ObjectIdentifier - expectedKeyUsageName := "" - if c.IsCA { - expectedKeyUsage = OidExtensionTcgDiceKpEca - expectedKeyUsageName = "tcg-dice-kp-eca" - } else { - expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc - expectedKeyUsageName = "tcg-dice-kp-attest-loc" + // Check vendorInfo field in multitcb + if err = checkDiceTcbVendorInfo(childTcbInfo, d.GetLocality()); err != nil { + t.Errorf("[ERROR]: %v", err) } - for _, oid := range extKeyUsage { - if oid.Equal(expectedKeyUsage) { - isExtendedKeyUsageValid = true - break - } + // Check tci type field in multitcb + if err = checkCurrentDiceTcbTciType(childTcbInfo, tciType); err != nil { + t.Errorf("[ERROR]: %v", err) } - if !isExtendedKeyUsageValid { - t.Errorf("[ERROR]: Certificate has IsCA: %v and does not contain specified key usage: %s", c.IsCA, expectedKeyUsageName) - } - return multiTcbInfo, err -} - -// Checks for KeyUsage Extension as per spec -// If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign -// If IsCA = false, KeyUsage extension MUST contain only DigitalSignature -func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) { - t.Helper() - //Check for keyusage extension - var allowedKeyUsages x509.KeyUsage - if c.IsCA { - allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign - } else { - allowedKeyUsages = x509.KeyUsageDigitalSignature + // Check hash algorithm field in multitcb + if err = checkDiceTcbHashAlgorithm(childTcbInfo, hashAlg); err != nil { + t.Errorf("[ERROR]: %v", err) } - certKeyUsageList := getKeyUsageNames(c.KeyUsage) - allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) - if c.KeyUsage != allowedKeyUsages { - t.Errorf("[ERROR]: Certificate has IsCA: %v and has got %v but want %v ", c.IsCA, certKeyUsageList, allowedKeyUsageList) + // Extend TCI support is mandatory for this validation + if !d.GetSupport().ExtendTci { + t.Errorf("ExtendTCI is unsupported by profile, unable to run tests to verify TCI_CUMULATIVE measurement") + return } -} - -// Validates basic constraints in certificate returned by CertifyKey command -// against the flag set for input parameter. -// The BasicConstraints extension MUST be included -// If CertifyKey AddIsCA is set, IsCA MUST be set to true. -// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false -func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags CertifyKeyFlags) { - t.Helper() - - flagsBuf := &bytes.Buffer{} - binary.Write(flagsBuf, binary.LittleEndian, flags) - - flagIsCA := CertifyAddIsCA&flags != 0 - if flagIsCA != c.IsCA { - t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, c.IsCA) + // Check dice tcb measurements of derived children + // Add one more child context + childTCI2 := make([]byte, digestLen) + for i := range childTCI2 { + childTCI2[i] = byte(i + 2) } -} - -// Validates X509 fields in certificate returned by CertifyKey command. -func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags CertifyKeyFlags, label []byte) { - t.Helper() - - // Check for basic constraints extension - checkCertifyKeyBasicConstraints(t, c, CertifyKeyFlags(flags)) - // Check key usage extensions - DigitalSignature, CertSign - checkCertifyKeyExtensions(t, c) - - // Check extended key usage extensions - checkCertifyKeyExtendedKeyUsages(t, c) - - // Check critical UEID and Multi Tcb Info TCG extensions - // Check UEID extension - checkCertifyKeyTcgUeidExtension(t, c, label) + childCtx, err = c.DeriveChild(childHandle, + childTCI2, + DeriveChildFlags(InputAllowX509), + tciType, + 0) - // Check MultiTcbInfo Extension structure - _, err := getMultiTcbInfo(c) if err != nil { - t.Error(err) + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } -} -// Parses X509 certificate -func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { - t.Helper() - failed := false - - var x509Cert *x509.Certificate - var err error - - // Check whether certificate is DER encoded. - if x509Cert, err = x509.ParseCertificate(certBytes); err != nil { - t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) - } - - // Parse the cert with zcrypto so we can lint it. - cert, err := zx509.ParseCertificate(certBytes) - if err != nil { - t.Errorf("[ERROR]: Could not parse certificate using zcrypto/x509: %v", err) - failed = true - } + childHandle = &childCtx.NewContextHandle - // zlint provides a lot of linter sources. Limit results to just the relevant RFCs. - // For a full listing of supported linter sources, see https://github.com/zmap/zlint/blob/master/v3/lint/source.go - registry, err := lint.GlobalRegistry().Filter(lint.FilterOptions{ - IncludeSources: lint.SourceList{ - lint.RFC3279, - lint.RFC5280, - lint.RFC5480, - lint.RFC5891, - lint.RFC8813, - }, - ExcludeNames: []string{ - // It is fine for cert chains to always use GeneralizedTime, UTCTime is - // strictly worse and mixing the two formats does not lend itself well - // to fixed-sized X.509 templating. - "e_wrong_time_format_pre2050", - }, - }) + // Get latest TCB information + certifiedKey, err := c.CertifyKey(childHandle, childTCI2, CertifyKeyX509, 0) if err != nil { - t.Fatalf("[FATAL]: Could not set up zlint registry: %v", err) + t.Fatalf("[FATAL]: Could not certify key: %s", err) } - results := zlint.LintCertificateEx(cert, registry) + childHandle = &certifiedKey.Handle + leafCertBytes := certifiedKey.Certificate - for id, result := range results.Results { - var level string - switch result.Status { - case lint.Error: - level = "ERROR" - case lint.Warn: - level = "WARN" - default: - continue - } - details := result.Details - if details != "" { - details = fmt.Sprintf("%s. ", details) - } - l := registry.ByName(id) - // TODO(https://github.com/chipsalliance/caliptra-dpe/issues/74): - // Fail the test with Errorf here once we expect it to pass. - t.Logf("[LINT %s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) - failed = true + // Build list of tci_current for validation and use it for validating TCI measurements + currentTCIs := [][]byte{childTCI2, childTCI1} + if err = validateDiceTcbFwids(leafCertBytes, currentTCIs, digestLen); err != nil { + t.Errorf("[ERROR]: %v", err) } - - if failed { - // Dump the cert in PEM and hex for use with various tools - t.Logf("[LINT]: Offending certificate: %s\n", cert.Subject.String()) - t.Logf("[LINT]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: certBytes, - }))) - } - return x509Cert } -func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { - handle := getInitialContextHandle(d, c, t, simulation) - defer func() { - if simulation { - c.DestroyContext(handle, DestroyDescendants) - } - }() - +// Checks Multi Tcb Info for context derived from simulation mode +func checkWithDerivedChildContextSimulation(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) *ContextHandle { profile, err := GetTransportProfile(d) if err != nil { t.Fatalf("Could not get profile: %v", err) @@ -717,153 +318,103 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo hashAlg = OidSHA256 } else if digestLen == 48 { hashAlg = OidSHA384 - } else { - t.Fatal("Unknown Hash Algorithm") } - seqLabel := make([]byte, digestLen) - for i := range seqLabel { - seqLabel[i] = byte(i) + childTCI := make([]byte, digestLen) + for i := range childTCI { + childTCI[i] = byte(i) } - certifyKeyParams := []CertifyKeyParams{ - {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, - {Label: seqLabel, Flags: CertifyKeyFlags(0)}, - } + // Set tciType to verify in UEID extension + tciType := uint32(2) - for _, params := range certifyKeyParams { - // Get DPE leaf certificate from CertifyKey - certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) - } + locality := d.GetLocality() - // Get root and intermediate certificates to validate certificate chain of leaf cert - certChainBytes, err := c.GetCertificateChain() - if err != nil { - t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) - } - - leafCertBytes := certifyKeyResp.Certificate - - // Run X.509 linter on full certificate chain and file issues for errors - leafCert := checkCertificateStructure(t, leafCertBytes) - certChain := checkCertificateChain(t, certChainBytes) - - // Check default context handle is unchanged - checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) - - // Check key returned in command response against certificate - checkCertifyKeyResponse(t, leafCert, *certifyKeyResp, hashAlg) - - // Validate that all X.509 fields conform with the format defined in the DPE iRoT profile - validateCertifyKeyCert(t, leafCert, params.Flags, params.Label) - - // Ensure full certificate chain has valid signatures - // This also checks certificate lifetime, signatures as part of cert chain validation - validateLeafCertChain(t, certChain, leafCert) + // Derive Child context with input data, tag it and check TCI_CUMULATIVE + childCtx, err := c.DeriveChild(handle, + childTCI, + DeriveChildFlags(InputAllowX509|ChangeLocality|RetainParent), + tciType, + locality+1) // Switch locality to derive child context from Simulation context - // Reassign handle for simulation mode. - // However, this does not impact in default mode because - // same default context handle is returned in default mode. - handle = &certifyKeyResp.Handle + if err != nil { + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - // TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again. -} -// Builds and verifies certificate chain. -func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { - t.Helper() - certsToProcess := []*x509.Certificate{leafCert} + handle = &childCtx.NewContextHandle + parentHandle := &childCtx.ParentContextHandle - // Remove unhandled critical extensions reported by x509 but defined in spec - removeTcgDiceCriticalExtensions(t, certsToProcess) + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) + } + // Revert locality for other tests + d.SetLocality(0) + }() - // Remove unhandled extended key usages reported by x509 but defined in spec - removeTcgDiceExtendedKeyUsages(t, certsToProcess) + // Switch to simulated child context locality to issue CertifyKey command + d.SetLocality(locality + 1) - // Build verify options - opts := buildVerifyOptions(t, certChain) + // Make CertifyKey call and get current MultiTcbInfo + var leafCert *x509.Certificate - // Certificate chain validation for leaf - chains, err := leafCert.Verify(opts) + certifiedKey, err := c.CertifyKey(handle, childTCI, CertifyKeyX509, 0) if err != nil { - // Certificate chain cannot be built from leaf to root - t.Errorf("[ERROR]: Error verifying DPE leaf: %s", err.Error()) - } - - // Log certificate chains linked to leaf - if len(chains) != 1 { - t.Errorf("[ERROR]: Unexpected number of cert chains: %d", len(chains)) - } -} - -// Builds Certificate chain verifier parameters. -func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions { - roots := x509.NewCertPool() - intermediates := x509.NewCertPool() - - // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. - roots.AddCert(certChain[0]) - - for _, cert := range certChain[1:] { - if cert.Subject.String() == cert.Issuer.String() { - t.Errorf("[ERROR]: Found a self-signed certificate in middle of certificate chain returned by GetCertificateChain.") - continue - } - intermediates.AddCert(cert) - } - opts := x509.VerifyOptions{ - Roots: roots, - Intermediates: intermediates, - CurrentTime: time.Now().UTC(), - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + t.Errorf("[ERROR]: Could not certify key: %s", err) } - return opts -} - -// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. -func getKeyUsageNames(keyUsage x509.KeyUsage) []string { - keyUsageNames := []string{} + handle = &certifiedKey.Handle // Update handle + leafCertBytes := certifiedKey.Certificate - if keyUsage&x509.KeyUsageDigitalSignature != 0 { - keyUsageNames = append(keyUsageNames, "DigitalSignature") + if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { + t.Errorf("[ERROR]: Could not parse certificate: %s", err) } - if keyUsage&x509.KeyUsageContentCommitment != 0 { - keyUsageNames = append(keyUsageNames, "ContentCommitment") + multiTcbInfo, err := getMultiTcbInfo(leafCert) + if err != nil { + t.Errorf("[ERROR]: Could not parse multi TCB info extension: %s", err) } - if keyUsage&x509.KeyUsageKeyEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "KeyEncipherment") + if len(multiTcbInfo) == 0 { + t.Errorf("[ERROR]: Certificate MutliTcbInfo is empty") } - if keyUsage&x509.KeyUsageDataEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "DataEncipherment") + childTcbInfo := multiTcbInfo[0] + if !bytes.Equal(childTcbInfo.Fwids[0].Digest, childTCI) { + t.Errorf("[ERROR]: Got current TCI %x, expected %x", childTcbInfo.Fwids[0].Digest, childTCI) } - if keyUsage&x509.KeyUsageKeyAgreement != 0 { - keyUsageNames = append(keyUsageNames, "KeyAgreement") + // Preform checks on multi Tcb info of child TCI node + // Check vendorInfo field + if err = checkDiceTcbVendorInfo(childTcbInfo, d.GetLocality()); err != nil { + t.Errorf("[ERROR]: %v", err) } - if keyUsage&x509.KeyUsageCertSign != 0 { - keyUsageNames = append(keyUsageNames, "CertSign") + // Check type field + if err = checkCurrentDiceTcbTciType(childTcbInfo, tciType); err != nil { + t.Errorf("[ERROR]: %v", err) } - if keyUsage&x509.KeyUsageCRLSign != 0 { - keyUsageNames = append(keyUsageNames, "CRLSign") + // Check hash algorithm + if err = checkDiceTcbHashAlgorithm(childTcbInfo, hashAlg); err != nil { + t.Errorf("[ERROR]: %v", err) } - if keyUsage&x509.KeyUsageEncipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "EncipherOnly") + // Extend TCI support is mandatory for this validation + if !d.GetSupport().ExtendTci { + t.Errorf("ExtendTCI is unsupported by profile, unable to run tests to verify TCI_CUMULATIVE measurements") + return parentHandle } - if keyUsage&x509.KeyUsageDecipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "DecipherOnly") + // Check all dice tcb measurements + // Build list of tci_current for validation + currentTCIs := [][]byte{childTCI} + if err = validateDiceTcbFwids(certifiedKey.Certificate, currentTCIs, digestLen); err != nil { + t.Errorf("[ERROR]: %v", err) } - - return keyUsageNames + return parentHandle } // Checks CertifyKey command response against public key extracted from certificate returned in response @@ -920,3 +471,77 @@ func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHa t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle) } } + +// Parses X509 certificate +func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { + failed := false + + var x509Cert *x509.Certificate + var err error + + // Check whether certificate is DER encoded. + if x509Cert, err = x509.ParseCertificate(certBytes); err != nil { + t.Fatalf("Could not parse certificate using crypto/x509: %v", err) + } + + // Parse the cert with zcrypto so we can lint it. + cert, err := zx509.ParseCertificate(certBytes) + if err != nil { + t.Errorf("Could not parse certificate using zcrypto/x509: %v", err) + failed = true + } + + // zlint provides a lot of linter sources. Limit results to just the relevant RFCs. + // For a full listing of supported linter sources, see https://github.com/zmap/zlint/blob/master/v3/lint/source.go + registry, err := lint.GlobalRegistry().Filter(lint.FilterOptions{ + IncludeSources: lint.SourceList{ + lint.RFC3279, + lint.RFC5280, + lint.RFC5480, + lint.RFC5891, + lint.RFC8813, + }, + ExcludeNames: []string{ + // It is fine for cert chains to always use GeneralizedTime, UTCTime is + // strictly worse and mixing the two formats does not lend itself well + // to fixed-sized X.509 templating. + "e_wrong_time_format_pre2050", + }, + }) + if err != nil { + t.Fatalf("[FATAL]: Could not set up zlint registry: %v", err) + } + + results := zlint.LintCertificateEx(cert, registry) + + for id, result := range results.Results { + var level string + switch result.Status { + case lint.Error: + level = "ERROR" + case lint.Warn: + level = "WARN" + default: + continue + } + details := result.Details + if details != "" { + details = fmt.Sprintf("%s. ", details) + } + l := registry.ByName(id) + // TODO(https://github.com/chipsalliance/caliptra-dpe/issues/74): + // Fail the test with Errorf here once we expect it to pass. + t.Logf("[LINT %s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) + failed = true + } + + if failed { + // Dump the cert in PEM and hex for use with various tools + t.Logf("[LINT]: Offending certificate: %s\n", cert.Subject.String()) + t.Logf("[LINT]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }))) + } + return x509Cert +} diff --git a/verification/client.go b/verification/client.go index cc3f11b0..6f6109a1 100755 --- a/verification/client.go +++ b/verification/client.go @@ -42,7 +42,6 @@ type DPESignedHash struct { type DPEClient interface { InitializeContext(flags InitCtxFlags) (*ContextHandle, error) GetProfile() (*GetProfileResp, error) - DeriveChild(handle *ContextHandle, inputData []byte, flags DeriveChildFlags, tciType uint32, targetLocality uint32) (*DeriveChildResp, error) CertifyKey(handle *ContextHandle, label []byte, format CertifyKeyFormat, flags CertifyKeyFlags) (*CertifiedKey, error) GetCertificateChain() ([]byte, error) DestroyContext(handle *ContextHandle, flags DestroyCtxFlags) error From aa5b38a769b8c2f936e8c9cd4c4fae8bf2d2d710 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 28 Nov 2023 21:59:20 +0530 Subject: [PATCH 07/17] rebase --- verification/go.mod | 2 -- verification/go.sum | 11 +++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/verification/go.mod b/verification/go.mod index eeb62908..1d6204bf 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -5,7 +5,6 @@ go 1.20 require ( github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 github.com/zmap/zlint/v3 v3.4.1 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 ) require ( @@ -13,7 +12,6 @@ require ( github.com/stretchr/testify v1.8.3 // indirect github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/net v0.8.0 // indirect golang.org/x/text v0.8.0 // indirect ) diff --git a/verification/go.sum b/verification/go.sum index 674a22ee..2a3049a9 100644 --- a/verification/go.sum +++ b/verification/go.sum @@ -58,11 +58,8 @@ golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -73,9 +70,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -105,9 +101,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From 31dc764af441342131f0dafb544921dfe39d1d4f Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 28 Nov 2023 22:34:24 +0530 Subject: [PATCH 08/17] update --- verification/abi.go | 95 ------ verification/certs.go | 503 +++++++++++++++++++++++++++- verification/extendTCI.go | 34 +- verification/getCertificateChain.go | 16 +- verification/go.mod | 16 +- verification/go.sum | 53 +-- verification/simulator.go | 8 +- verification/verification.go | 12 +- 8 files changed, 574 insertions(+), 163 deletions(-) diff --git a/verification/abi.go b/verification/abi.go index fdaa0148..63f76607 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -69,21 +69,6 @@ const ( type ContextHandle [16]byte -type RotateContextHandleFlags uint32 - -const ( - TargetIsDefault RotateContextHandleFlags = 1 << 31 -) - -type RotateContextHandleCmd struct { - Handle ContextHandle - Flags RotateContextHandleFlags -} - -type RotatedContextHandle struct { - NewContextHandle ContextHandle -} - type DestroyCtxFlags uint32 const ( @@ -117,31 +102,6 @@ type GetProfileResp struct { Flags uint32 } -type DeriveChildFlags uint32 - -const ( - InternalInputInfo DeriveChildFlags = 1 << 31 - InternalInputDice DeriveChildFlags = 1 << 30 - RetainParent DeriveChildFlags = 1 << 29 - MakeDefault DeriveChildFlags = 1 << 28 - ChangeLocality DeriveChildFlags = 1 << 27 - InputAllowCA DeriveChildFlags = 1 << 26 - InputAllowX509 DeriveChildFlags = 1 << 25 -) - -type DeriveChildReq[Digest DigestAlgorithm] struct { - ContextHandle ContextHandle - InputData Digest - Flags DeriveChildFlags - TciType uint32 - TargetLocality uint32 -} - -type DeriveChildResp struct { - NewContextHandle ContextHandle - ParentContextHandle ContextHandle -} - type CertifyKeyFlags uint32 const ( @@ -169,25 +129,6 @@ type CertifyKeyResp[CurveParameter Curve, Digest DigestAlgorithm] struct { Certificate []byte } -type SignFlags uint32 - -const ( - IsSymmetric SignFlags = 1 << 30 -) - -type SignReq[Digest DigestAlgorithm] struct { - ContextHandle ContextHandle - Label Digest - Flags SignFlags - ToBeSigned Digest -} - -type SignResp[Digest DigestAlgorithm] struct { - NewContextHandle ContextHandle - HmacOrSignatureR Digest - SignatureS Digest -} - type GetCertificateChainReq struct { Offset uint32 Size uint32 @@ -440,42 +381,6 @@ func (c *dpeABI[CurveParameter, Digest]) CertifyKeyABI(cmd *CertifyKeyReq[Digest }, nil } -// DeriveChild calls DPE DeriveChild command. -func (c *dpeABI[_, Digest]) DeriveChildABI(cmd *DeriveChildReq[Digest]) (*DeriveChildResp, error) { - var respStruct DeriveChildResp - - _, err := execCommand(c.transport, CommandDeriveChild, c.Profile, cmd, &respStruct) - if err != nil { - return nil, err - } - - return &respStruct, err -} - -// RotateContext calls DPE RotateContextHandle command. -func (c *dpeABI[_, Digest]) RotateContextABI(cmd *RotateContextHandleCmd) (*RotatedContextHandle, error) { - var respStruct RotatedContextHandle - - _, err := execCommand(c.transport, CommandRotateContextHandle, c.Profile, cmd, &respStruct) - if err != nil { - return nil, err - } - - return &respStruct, err -} - -// Sign calls the DPE Sign command. -func (c *dpeABI[_, Digest]) SignABI(cmd *SignReq[Digest]) (*SignResp[Digest], error) { - var respStruct SignResp[Digest] - - _, err := execCommand(c.transport, CommandSign, c.Profile, cmd, &respStruct) - if err != nil { - return nil, err - } - - return &respStruct, nil -} - // GetCertificateChain calls the DPE GetCertificateChain command. func (c *dpeABI[_, _]) GetCertificateChainABI() (*GetCertificateChainResp, error) { var certs GetCertificateChainResp diff --git a/verification/certs.go b/verification/certs.go index 1dc83a8b..475dc37c 100644 --- a/verification/certs.go +++ b/verification/certs.go @@ -3,11 +3,113 @@ package verification import ( + "bytes" "crypto/x509" "encoding/asn1" + "encoding/binary" "fmt" + "reflect" + "time" + + "golang.org/x/exp/slices" +) + +var ( + OidExtensionAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35} + OidExtensionBasicConstraints = asn1.ObjectIdentifier{2, 5, 29, 19} + OidExtensionExtKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 37} + OidExtensionTcgDiceUeid = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 4} + OidExtensionTcgDiceMultiTcbInfo = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 5} + OidExtensionTcgDiceKpIdentityInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 6} + OidExtensionTcgDiceKpIdentityLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 7} + OidExtensionTcgDiceKpAttestInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 8} + OidExtensionTcgDiceKpAttestLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 9} + OidExtensionTcgDiceKpAssertInit = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 10} + OidExtensionTcgDiceKpAssertLoc = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 11} + OidExtensionTcgDiceKpEca = asn1.ObjectIdentifier{2, 23, 133, 5, 4, 100, 12} + OidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} + OidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} +) + +var TcgDiceCriticalExtensions = [...]string{ + OidExtensionTcgDiceMultiTcbInfo.String(), + OidExtensionTcgDiceUeid.String(), +} + +var TcgDiceExtendedKeyUsages = [...]string{ + OidExtensionTcgDiceKpIdentityLoc.String(), + OidExtensionTcgDiceKpAttestLoc.String(), +} + +// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} +// +// TcgUeid ::== SEQUENCE { +// ueid OCTET STRING +// } +type TcgUeidExtension struct { + Ueid []uint8 `asn1:"ueid,implicit"` +} + +// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} +// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo +// +// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} +// +// DiceTcbInfo ::== SEQUENCE { +// vendor [0] IMPLICIT UTF8String OPTIONAL, +// model [1] IMPLICIT UTF8String OPTIONAL, +// version [2] IMPLICIT UTF8String OPTIONAL, +// svn [3] IMPLICIT INTEGER OPTIONAL, +// layer [4] IMPLICIT INTEGER OPTIONAL, +// index [5] IMPLICIT INTEGER OPTIONAL, +// fwids [6] IMPLICIT FWIDLIST OPTIONAL, +// flags [7] IMPLICIT OperationalFlags OPTIONAL, +// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, +// type [9] IMPLICIT OCTET STRING OPTIONAL, +// } +// +// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID +// FWID ::== SEQUENCE { +// hashAlg OBJECT IDENTIFIER, +// digest OCTET STRING +// } +// +// OperationalFlags ::= BIT STRING { +// notConfigured (0), +// notSecure (1), +// recovery (2), +// debug (3) +// } + +type Fwid struct { + HashAlg asn1.ObjectIdentifier + Digest []byte +} + +type DiceTcbInfo struct { + Vendor string `asn1:"optional,tag:0,utf8"` + Model string `asn1:"optional,tag:1,utf8"` + Version string `asn1:"optional,tag:2,utf8"` + SVN int `asn1:"optional,tag:3"` + Layer int `asn1:"optional,tag:4"` + Index int `asn1:"optional,tag:5"` + Fwids []Fwid `asn1:"optional,tag:6"` + Flags OperationalFlag `asn1:"optional,tag:7"` + VendorInfo []byte `asn1:"optional,tag:8"` + Type []byte `asn1:"optional,tag:9"` +} + +type OperationalFlag int + +const ( + NotConfigured OperationalFlag = iota + NotSecure + Debug + Recovery ) +type TcgMultiTcbInfo = []DiceTcbInfo + // A tcg-dice-MultiTcbInfo extension. // This extension SHOULD be marked as critical. func getMultiTcbInfo(c *x509.Certificate) (TcgMultiTcbInfo, error) { @@ -18,12 +120,12 @@ func getMultiTcbInfo(c *x509.Certificate) (TcgMultiTcbInfo, error) { for _, ext := range c.Extensions { if ext.Id.Equal(OidExtensionTcgDiceMultiTcbInfo) { // OID for Tcg Dice MultiTcbInfo if !ext.Critical { - return multiTcbInfo, fmt.Errorf("[ERROR]: TCG DICE MultiTcbInfo extension is not marked as CRITICAL") + return multiTcbInfo, fmt.Errorf("multiTcbInfo extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &multiTcbInfo) if err != nil { // multiTcb info is not provided in leaf - return multiTcbInfo, fmt.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) + return multiTcbInfo, fmt.Errorf("failed to unmarshal MultiTcbInfo field: %v", err) } break } @@ -37,7 +139,7 @@ func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (*ContextHandle, Di // Get digest size profile, err := c.GetProfile() if err != nil { - return outHandle, DiceTcbInfo{}, fmt.Errorf("Cannot get profile: %s", err) + return outHandle, DiceTcbInfo{}, fmt.Errorf("cannot get profile: %s", err) } digestLen := profile.Profile.GetDigestSize() @@ -45,7 +147,7 @@ func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (*ContextHandle, Di certifiedKey, err := c.CertifyKey(outHandle, label, CertifyKeyX509, 0) if err != nil { - return outHandle, DiceTcbInfo{}, fmt.Errorf("Could not certify key: %s", err) + return outHandle, DiceTcbInfo{}, fmt.Errorf("could not certify key: %s", err) } outHandle = &certifiedKey.Handle @@ -65,8 +167,399 @@ func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (*ContextHandle, Di } if len(multiTcbInfo) == 0 { - return outHandle, DiceTcbInfo{}, fmt.Errorf("Certificate MutliTcbInfo is empty") + return outHandle, DiceTcbInfo{}, fmt.Errorf("certificate MutliTcbInfo is empty") } return outHandle, multiTcbInfo[0], nil } + +// Removes the critical extensions that are unknown to x509 package +// but defined in DPE certificate profile specification for cert chain validation +// UnhandledCriticalExtensions may have only custom extensions mentioned in spec +// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec +// positive case expects the unknownExtnMap to be empty. +func removeTcgDiceCriticalExtensions(certs []*x509.Certificate) error { + unknownExtnMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnhandledCriticalExtensions) > 0 { + unknownExtns := []string{} + for _, extn := range cert.UnhandledCriticalExtensions { + if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { + unknownExtns = append(unknownExtns, extn.String()) + } + } + + if len(unknownExtnMap) == 0 { + cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} + } else { + unknownExtnMap[cert.Subject.String()] = unknownExtns + } + } + } + // The error details in this map will be logged + msg := "" + if len(unknownExtnMap) > 0 { + for certSubject, ext := range unknownExtnMap { + msg += fmt.Errorf("certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() + } + return fmt.Errorf("%s", msg) + } + return nil +} + +// Ignores extended key usages that are unknown to x509 package +// but atleast defined in DPE certificate profile specification for cert chain validation +// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec +// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec +// positive case expects the unknownKeyUsagesMap to be empty. +func removeTcgDiceExtendedKeyUsages(certs []*x509.Certificate) error { + unknownKeyUsagesMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnknownExtKeyUsage) > 0 { + unknownKeyUsages := []string{} + for _, eku := range cert.UnknownExtKeyUsage { + if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { + unknownKeyUsages = append(unknownKeyUsages, eku.String()) + } + } + + if len(unknownKeyUsagesMap) == 0 { + cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} + } else { + unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages + } + } + } + // The error details in this map will be logged + msg := "" + if len(unknownKeyUsagesMap) > 0 { + for certSubject, ext := range unknownKeyUsagesMap { + msg += fmt.Errorf("certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() + } + return fmt.Errorf("%s", msg) + } + return nil +} + +// A tcg-dice-Ueid extension MUST be added +// UEID extension be populated by the LABEL input parameter to CertifyKey command +// The extension SHOULD be marked as critical +func checkTcgUeidExtension(c *x509.Certificate, label []byte) error { + isFound := false + // Check UEID extension + for _, ext := range c.Extensions { + if ext.Id.Equal(OidExtensionTcgDiceUeid) { + isFound = true + if !ext.Critical { + return fmt.Errorf("tcg-dice-Ueid extension is NOT marked as CRITICAL") + } + var ueid TcgUeidExtension = TcgUeidExtension{} + _, err := asn1.Unmarshal(ext.Value, &ueid) + if err != nil { + return fmt.Errorf("unable to unmarshal value of UEID extension, %s", err.Error()) + } + + if !reflect.DeepEqual(ueid.Ueid, label) { + // Ueid extn value doen not match the label + return fmt.Errorf("tcg-dice-Ueid value does not match with the \"Label\" of certified key") + } + break + } + } + if !isFound { + return fmt.Errorf("tcg-dice-Ueid extension is missing") + } + return nil +} + +// Checks whether the VendorInfo is 4-bytes TARGET_LOCALITY parameter +func checkDiceTcbVendorInfo(currentTcbInfo DiceTcbInfo, targetLocality uint32) error { + var err error + expectedVendorInfo := make([]byte, 4) + binary.BigEndian.PutUint32(expectedVendorInfo, targetLocality) + if !bytes.Equal(currentTcbInfo.VendorInfo, expectedVendorInfo) { + err = fmt.Errorf("unexpected VendorInfo for current DICE TCB block, want %v but got %v", expectedVendorInfo, currentTcbInfo.VendorInfo) + } + return err +} + +// Checks whether INPUT_TYPE passed to a deriveChild Request +// populates the "type" field in the DiceTcbInfo extension. +func checkCurrentDiceTcbTciType(currentTcbInfo DiceTcbInfo, expectedTciType uint32) error { + var err error + expectedTciTypeBytes := make([]byte, 4) + binary.BigEndian.PutUint32(expectedTciTypeBytes, expectedTciType) + if !bytes.Equal(currentTcbInfo.Type, expectedTciTypeBytes) { + err = fmt.Errorf("unexpected TCI type for current DICE TCB block, want %v but got %v", expectedTciTypeBytes, currentTcbInfo.Type) + } + return err +} + +// Checks whether the Hash Algorithm field in FWID block is correct +func checkDiceTcbHashAlgorithm(currentTcbInfo DiceTcbInfo, hashAlg asn1.ObjectIdentifier) error { + for _, fwid := range currentTcbInfo.Fwids { + if !fwid.HashAlg.Equal(hashAlg) { + return fmt.Errorf("unexpected hash algorithm in FWID block, expected %s but got %s", hashAlg, fwid.HashAlg) + } + } + return nil +} + +// Checks whether certificate extended key usage is as per spec +// OID for ExtendedKeyUsage Extension: 2.5.29.37 +// The ExtendedKeyUsage extension SHOULD be marked as critical +// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca +// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc +func checkExtendedKeyUsages(c *x509.Certificate) error { + extKeyUsage := []asn1.ObjectIdentifier{} + + for _, ext := range c.Extensions { + if ext.Id.Equal(OidExtensionExtKeyUsage) { // OID for ExtKeyUsage extension + // Extract the OID value from the extension + _, err := asn1.Unmarshal(ext.Value, &extKeyUsage) + if err != nil { + return fmt.Errorf("unable to unmarshal the Extended Key Usage extension: %v", err) + } + + if !ext.Critical { + return fmt.Errorf("extended key usage is not marked critical") + } + break + } + } + + if len(extKeyUsage) == 0 { + return fmt.Errorf("extended key usage is empty") + } + + // Iterate over the OIDs in the ExtKeyUsage extension + isExtendedKeyUsageValid := false + var expectedKeyUsage asn1.ObjectIdentifier + expectedKeyUsageName := "" + if c.IsCA { + expectedKeyUsage = OidExtensionTcgDiceKpEca + expectedKeyUsageName = "tcg-dice-kp-eca" + } else { + expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc + expectedKeyUsageName = "tcg-dice-kp-attest-loc" + } + + for _, oid := range extKeyUsage { + if oid.Equal(expectedKeyUsage) { + isExtendedKeyUsageValid = true + break + } + } + if !isExtendedKeyUsageValid { + return fmt.Errorf("certificate has IsCA: %v and does not contain specified key usage: %s", c.IsCA, expectedKeyUsageName) + } + return nil +} + +// Checks for KeyUsage Extension as per spec +// If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign +// If IsCA = false, KeyUsage extension MUST contain only DigitalSignature +func checkKeyExtensions(c *x509.Certificate) error { + var allowedKeyUsages x509.KeyUsage + var err error + + if c.IsCA { + allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign + } else { + allowedKeyUsages = x509.KeyUsageDigitalSignature + } + + certKeyUsageList := getKeyUsageNames(c.KeyUsage) + allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) + if c.KeyUsage != allowedKeyUsages { + err = fmt.Errorf("certificate has IsCA: %v and has got %v but want %v", c.IsCA, certKeyUsageList, allowedKeyUsageList) + } + return err + +} + +// Validates basic constraints in certificate against the input flag passed to CertifyKey command +// BasicConstraints extension MUST be included +// If CertifyKey AddIsCA is set, IsCA MUST be set to true. +// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false +func checkBasicConstraints(c *x509.Certificate, flags CertifyKeyFlags) error { + var err error + flagsBuf := &bytes.Buffer{} + binary.Write(flagsBuf, binary.LittleEndian, flags) + + flagIsCA := CertifyAddIsCA&flags != 0 + if flagIsCA != c.IsCA { + err = fmt.Errorf("basic constraint IsCA must be %v, got %v", flagIsCA, c.IsCA) + } + return err +} + +// Builds and verifies certificate chain. +func validateLeafCertChain(certChain []*x509.Certificate, leafCert *x509.Certificate) error { + var err error + certsToProcess := []*x509.Certificate{leafCert} + + // Remove unhandled critical extensions reported by x509 but defined in spec + if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { + return err + } + + // Remove unhandled extended key usages reported by x509 but defined in spec + if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { + return err + } + + // Build verify options + var opts *x509.VerifyOptions + if opts, err = buildVerifyOptions(certChain); err != nil { + return err + } + + // Certificate chain validation for leaf + chains, err := leafCert.Verify(*opts) + if err != nil { + // Unable to build certificate chain from leaf to root + return fmt.Errorf("error verifying DPE leaf: %s", err.Error()) + } + + // Log certificate chains linked to leaf + if len(chains) != 1 { + return fmt.Errorf("unexpected number of cert chains: %d", len(chains)) + } + return nil +} + +// Builds Certificate chain verifier parameters. +func buildVerifyOptions(certChain []*x509.Certificate) (*x509.VerifyOptions, error) { + var err error + roots := x509.NewCertPool() + intermediates := x509.NewCertPool() + + // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. + roots.AddCert(certChain[0]) + + for _, cert := range certChain[1:] { + if cert.Subject.String() == cert.Issuer.String() { + return nil, fmt.Errorf("found a self-signed certificate in middle of certificate chain returned by GetCertificateChain") + } + intermediates.AddCert(cert) + } + opts := x509.VerifyOptions{ + Roots: roots, + Intermediates: intermediates, + CurrentTime: time.Now().UTC(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + } + + return &opts, err +} + +// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. +func getKeyUsageNames(keyUsage x509.KeyUsage) []string { + keyUsageNames := []string{} + + if keyUsage&x509.KeyUsageDigitalSignature != 0 { + keyUsageNames = append(keyUsageNames, "DigitalSignature") + } + + if keyUsage&x509.KeyUsageContentCommitment != 0 { + keyUsageNames = append(keyUsageNames, "ContentCommitment") + } + + if keyUsage&x509.KeyUsageKeyEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "KeyEncipherment") + } + + if keyUsage&x509.KeyUsageDataEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "DataEncipherment") + } + + if keyUsage&x509.KeyUsageKeyAgreement != 0 { + keyUsageNames = append(keyUsageNames, "KeyAgreement") + } + + if keyUsage&x509.KeyUsageCertSign != 0 { + keyUsageNames = append(keyUsageNames, "CertSign") + } + + if keyUsage&x509.KeyUsageCRLSign != 0 { + keyUsageNames = append(keyUsageNames, "CRLSign") + } + + if keyUsage&x509.KeyUsageEncipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "EncipherOnly") + } + + if keyUsage&x509.KeyUsageDecipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "DecipherOnly") + } + + return keyUsageNames +} + +// Verifies the TCI_Current and TCI_Cumulative of dice tcb information blocks +func verifyDiceTcbDigest(tcbInfo DiceTcbInfo, wantCurrentTCI []byte, lastCumulativeTCI []byte) error { + var err error + + // Check TCI_CURRENT + currentTCI := tcbInfo.Fwids[0].Digest + if !bytes.Equal(currentTCI, wantCurrentTCI) { + err = fmt.Errorf("unexpected TCI_CURRENT digest, want %v but got %v", wantCurrentTCI, currentTCI) + } + + // Check TCI_CUMULATIVE against expected cumulative TCI + wantCumulativeTCI := computeExpectedCumulative(lastCumulativeTCI, currentTCI) + cumulativeTCI := tcbInfo.Fwids[1].Digest + if !bytes.Equal(cumulativeTCI, wantCumulativeTCI) { + err = fmt.Errorf("unexpected TCI_CUMULATIVE value, want %v but got %v", wantCumulativeTCI, cumulativeTCI) + } + return err +} + +// Checks the FWID block's Digest. +// FWID at index 0 has the TCI_CURRENT as digest +// FWID at index 1 has the TCI_CUMULATIVE as digest +// FWID array always has two digest/hashAlg blocks when "ExtendTci" is supported by DPE profile. +func validateDiceTcbFwids(leafCertBytes []byte, currentTcis [][]byte, digestLen int) error { + var leafCert *x509.Certificate + var err error + + // Check whether certificate is DER encoded. + if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { + return err + } + + // Get DICE information from MultiTcbInfo Extension + var multiTcbInfo []DiceTcbInfo + if multiTcbInfo, err = getMultiTcbInfo(leafCert); err != nil { + return err + } + + if len(multiTcbInfo) == 0 { + return fmt.Errorf("certificate MutliTcbInfo is empty") + } + + // Calculate expected cumulative value + defaultTci := make([]byte, digestLen) + + // Check cumulative, current TCI at the last index of multitcb info + // It must have default TCI value + lastIndex := len(multiTcbInfo) - 1 + if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[0].Digest, defaultTci) { + return fmt.Errorf("current TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[0].Digest) + } + + if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[1].Digest, defaultTci) { + return fmt.Errorf("cumulative TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[1].Digest) + } + + // Check cumulative, current TCI of other indices if any + lastCumulativeTCI := defaultTci + multiTcbInfo = multiTcbInfo[:lastIndex] + + for i, tcbinfo := range multiTcbInfo { + wantCurrentTci := currentTcis[i] + verifyDiceTcbDigest(tcbinfo, wantCurrentTci, lastCumulativeTCI) + } + return err +} diff --git a/verification/extendTCI.go b/verification/extendTCI.go index e46d1cdb..aa3a5c9f 100644 --- a/verification/extendTCI.go +++ b/verification/extendTCI.go @@ -35,7 +35,7 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { if err != nil { t.Fatal(err) } - lastCumulative := tcbInfo.Fwids[1].Digest + lastCumulativeTCI := tcbInfo.Fwids[1].Digest // Set current TCI value _, err = c.ExtendTCI(handle, tciValue) @@ -43,9 +43,17 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { t.Fatalf("[FATAL]: Could not extend TCI: %v", err) } - // Check current and cumulative measurement by CertifyKey - expectedCumulative := computeExpectedCumulative(lastCumulative, tciValue) - verifyMeasurements(c, t, handle, tciValue, expectedCumulative) + // Refresh TCB info + _, tcbInfo, err = getTcbInfoForHandle(c, handle) + if err != nil { + t.Fatal(err) + } + + // Check current and cumulative measurement in DiceTcb info block + wantCurrentTCI := tciValue + if err = verifyDiceTcbDigest(tcbInfo, wantCurrentTCI, lastCumulativeTCI); err != nil { + t.Errorf("[ERROR]: %v", err) + } } func computeExpectedCumulative(lastCumulative []byte, tciValue []byte) []byte { @@ -153,21 +161,3 @@ func TestExtendTciOnDerivedContexts(d TestDPEInstance, c DPEClient, t *testing.T t.Errorf("[ERROR]: Child node's cumulative TCI %x, expected %x", childTcbInfo.Fwids[1].Digest, wantCumulativeTCI) } } - -func verifyMeasurements(c DPEClient, t *testing.T, handle *ContextHandle, expectedCurrent []byte, expectedCumulative []byte) { - handle, tcbInfo, err := getTcbInfoForHandle(c, handle) - if err != nil { - t.Fatal(err) - } - - // Check that the last TcbInfo current/cumulative are as expected - current := tcbInfo.Fwids[0].Digest - cumulative := tcbInfo.Fwids[1].Digest - if !bytes.Equal(current, expectedCurrent) { - t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrent, current) - } - - if !bytes.Equal(cumulative, expectedCumulative) { - t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulative, cumulative) - } -} diff --git a/verification/getCertificateChain.go b/verification/getCertificateChain.go index 362ed85c..66f8662e 100644 --- a/verification/getCertificateChain.go +++ b/verification/getCertificateChain.go @@ -102,21 +102,29 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { // Build certificate chain and calls to validateSignature on each chain. func validateCertChain(t *testing.T, certChain []*x509.Certificate) { t.Helper() + var err error certsToProcess := certChain // Remove unhandled critical extensions reported by x509 but defined in spec - removeTcgDiceCriticalExtensions(t, certsToProcess) + if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Remove unhandled extended key usages reported by x509 but defined in spec - removeTcgDiceExtendedKeyUsages(t, certsToProcess) + if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Build verify options - opts := buildVerifyOptions(t, certChain) + opts, err := buildVerifyOptions(certChain) + if err != nil { + t.Errorf("[ERROR]: %v", err) + } // Certificate chain validation for each intermediate certificate for _, cert := range certChain { - chains, err := cert.Verify(opts) + chains, err := cert.Verify(*opts) if err != nil { t.Errorf("[ERROR]: Error in Certificate Chain of %s: %s", cert.Subject, err.Error()) } diff --git a/verification/go.mod b/verification/go.mod index 1d6204bf..16b8ad0f 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -3,15 +3,15 @@ module github.com/chipsalliance/caliptra-dpe/verification go 1.20 require ( - github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 - github.com/zmap/zlint/v3 v3.4.1 + github.com/zmap/zcrypto v0.0.0-20231106212110-94c8f62efae4 + github.com/zmap/zlint/v3 v3.5.0 ) require ( - github.com/pelletier/go-toml v1.9.3 // indirect - github.com/stretchr/testify v1.8.3 // indirect - github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/text v0.8.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20231127185646-65229373498e + golang.org/x/net v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect ) diff --git a/verification/go.sum b/verification/go.sum index 2a3049a9..abdf0d74 100644 --- a/verification/go.sum +++ b/verification/go.sum @@ -1,16 +1,18 @@ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= +github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -21,8 +23,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -32,12 +34,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs= -github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= +github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg= +github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= @@ -45,21 +46,23 @@ github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54t github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk= github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ= -github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 h1:YOQ1vXEwE4Rnj+uQ/3oCuJk5wgVsvUyW+glsndwYuyA= -github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21S5Z9bK1BMrertTGX/F8hgAPw7ERJRNS0= +github.com/zmap/zcrypto v0.0.0-20231106212110-94c8f62efae4 h1:YBEjlA0uAnTqljTgqFgA3NQUrcDSc850G2KuWnZ91UQ= +github.com/zmap/zcrypto v0.0.0-20231106212110-94c8f62efae4/go.mod h1:Z2SNNuFhO+AAsezbGEHTWeW30hHv5niUYT3fwJ61Nl0= github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= -github.com/zmap/zlint/v3 v3.4.1 h1:zhGB2Q1oPNS+bODC5tTPlKDOnLfDGyxejgAEp1SfFiQ= -github.com/zmap/zlint/v3 v3.4.1/go.mod h1:WgepL2QqxyMHnrOWJ54NqrgfMtOyuXr52wEE0tcfo9k= +github.com/zmap/zlint/v3 v3.5.0 h1:Eh2B5t6VKgVH0DFmTwOqE50POvyDhUaU9T2mJOe1vfQ= +github.com/zmap/zlint/v3 v3.5.0/go.mod h1:JkNSrsDJ8F4VRtBZcYUQSvnWFL7utcjDIn+FE64mlBI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -70,10 +73,12 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -85,24 +90,32 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -118,5 +131,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/verification/simulator.go b/verification/simulator.go index c3386067..991ced9e 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -231,13 +231,13 @@ func GetSimulatorTargets() []TestTarget { }, { "DefaultSupport", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), AllTestCases, }, { - "DeriveChildSupport", - getTestTarget([]string{"AutoInit", "InternalDice", "InternalInfo"}), - []TestCase{DeriveChildTestCase}, + "CertifyKey_WithoutExtendTci", + getTestTarget([]string{"AutoInit", "X509"}), + []TestCase{CertifyKeyWithoutExtendTciTestCase}, }, { "GetProfile_Simulation", diff --git a/verification/verification.go b/verification/verification.go index a41b4c1b..1360181e 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -26,14 +26,17 @@ var InitializeContextTestCase = TestCase{ var InitializeContextSimulationTestCase = TestCase{ "InitializeContextSimulation", TestInitializeSimulation, []string{"Simulation"}, } + +// ExtendTci is required for tci_cumulative in fwid, RotateContext handle for restore parent context after using child context var CertifyKeyTestCase = TestCase{ - "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA"}, + "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, } - var CertifyKeySimulationTestCase = TestCase{ - "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA"}, + "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, +} +var CertifyKeyWithoutExtendTciTestCase = TestCase{ + "CertifyKeyWithoutExtendTciSupport", TestCertifyKeyWithoutExtendTciSupport, []string{"AutoInit", "X509"}, } - var GetCertificateChainTestCase = TestCase{ "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, } @@ -73,7 +76,6 @@ var SignSymmetricTestCase = TestCase{ var SignSimulationTestCase = TestCase{ "SignSimulation", TestSignSimulation, []string{"Simulation"}, } - var DeriveChildTestCase = TestCase{ "AutoInit", TestDeriveChild, []string{"AutoInit", "InternalDice", "InternalInfo"}, } From da35b5c06ddcea7e1f08ced52ed10afad0f6dd47 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 28 Nov 2023 22:41:07 +0530 Subject: [PATCH 09/17] update --- verification/verification.go | 1 + 1 file changed, 1 insertion(+) diff --git a/verification/verification.go b/verification/verification.go index 1360181e..c5d10415 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -96,6 +96,7 @@ var AllTestCases = []TestCase{ InitializeContextSimulationTestCase, InvalidHandleTestCase, WrongLocalityTestCase, + DeriveChildTestCase, } func RunTargetTestCases(target TestTarget, t *testing.T) { From f689aee16a2e1330dd61a5beaad809d6fbffd317 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 28 Nov 2023 23:33:56 +0530 Subject: [PATCH 10/17] rebased code --- verification/deriveChild.go | 68 +++++++++++++----------------------- verification/verification.go | 4 +-- 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/verification/deriveChild.go b/verification/deriveChild.go index b2c3e9be..6b3eae3e 100644 --- a/verification/deriveChild.go +++ b/verification/deriveChild.go @@ -16,7 +16,7 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { } func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { - handle := &DefaultContextHandle + handle := getInitialContextHandle(d, c, t, false) // Get digest size profile, err := GetTransportProfile(d) @@ -26,10 +26,6 @@ func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { digestLen := profile.GetDigestSize() - // Test wrong locality - - testDeriveChildWrongLocality(t, d, c, handle, digestLen) - // Test child handles when MakeDefault flag is enabled/disabled testChildHandles(t, d, c, handle, digestLen) @@ -53,40 +49,18 @@ func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { // Test derive child contexts count limited by MAX_TCI_NODES supported by the profile testMaxTcis(t, d, c, handle, digestLen) -} - -// Checks whether caller from one locality is prevented from making DPE calls to other locality -func testDeriveChildWrongLocality(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - - var err error - - // Modify locality of DPE instance to test - d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) - - // Restore locality of DPE instance after the test - defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) - - _, err = c.DeriveChild(handle, - make([]byte, digestLen), - DeriveChildFlags(MakeDefault), - 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY) - - if err == nil { - t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusInvalidLocality) - } else if !errors.Is(err, StatusInvalidLocality) { - t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidLocality, err) - } + getInitialContextHandle(d, c, t, false) } // Check handle of default and non-default child func testChildHandles(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { // MakeDefault flag is not set + currentLocality := d.GetLocality() r, err := c.DeriveChild(handle, make([]byte, digestLen), ChangeLocality, 0, - DPE_SIMULATOR_OTHER_LOCALITY) + currentLocality+1) if err != nil { t.Fatalf("[FATAL]: Error while creating non-default child context handle: %s", err) @@ -100,13 +74,13 @@ func testChildHandles(t *testing.T, d TestDPEInstance, c DPEClient, handle *Cont existingTciNodeCount += 1 // MakeDefault flag is set - d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) + d.SetLocality(currentLocality + 1) defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) r, err = c.DeriveChild(&r.NewContextHandle, make([]byte, digestLen), MakeDefault|ChangeLocality, 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY, + currentLocality, ) if err != nil { @@ -144,11 +118,13 @@ func testMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *Conte // Checks default child handle creation in other locality. func testMakeDefaultInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + currentLocality := d.GetLocality() r, err := c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|ChangeLocality, 0, - DPE_SIMULATOR_OTHER_LOCALITY) + currentLocality+1, + ) if err != nil { t.Fatalf("[FATAL]: Error while creating default child handle in non-default context: %s", err) @@ -158,14 +134,14 @@ func testMakeDefaultInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPECl existingTciNodeCount += 1 // Revert hardware locality and handle for further tests - d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) - defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + d.SetLocality(currentLocality + 1) + defer d.SetLocality(currentLocality) _, err = c.DeriveChild(&r.NewContextHandle, make([]byte, digestLen), MakeDefault|ChangeLocality, 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY) + currentLocality) if err != nil { t.Fatalf("[FATAL]: Error while creating default child handle in default context: %s", err) @@ -178,7 +154,7 @@ func testMakeDefaultInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPECl // Checks whether the derived context does not escalate beyond the privileges of parent context. func testPrivilegeEscalation(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { var err error - escalatedChildPrivileges := []DeriveChildFlags{InputAllowCA, InputAllowX509} + escalatedChildPrivileges := []DeriveChildFlags{InternalInputDice, InternalInputDice} for _, flag := range escalatedChildPrivileges { _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|flag, 0, 0) @@ -194,11 +170,12 @@ func testPrivilegeEscalation(t *testing.T, d TestDPEInstance, c DPEClient, handl // This is because mixture of default and non-default handles are not allowed in this context. // Parent handle is invalidated in default context. func testRetainParentInDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + currentLocality := d.GetLocality() _, err := c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY) + currentLocality) if err == nil { t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusInvalidArgument) } else if !errors.Is(err, StatusInvalidArgument) { @@ -208,11 +185,12 @@ func testRetainParentInDefaultContext(t *testing.T, d TestDPEInstance, c DPEClie // Checks whether parent handle could be retained in a locality with non-default context. func testRetainParentInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + currentLocality := d.GetLocality() _, err := c.DeriveChild(handle, make([]byte, digestLen), RetainParent|ChangeLocality, 0, - DPE_SIMULATOR_OTHER_LOCALITY) + currentLocality+1) if err != nil { t.Fatalf("[FATAL]: Error while retaining parent handle in non-default context: %s", err) } @@ -226,11 +204,12 @@ func testRetainParentInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEC // tries to create two default context handles in the locality which is not allowed since a locality can have // only one default context handle. func testRetainParentAndMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { + currentLocality := d.GetLocality() _, err := c.DeriveChild(handle, make([]byte, digestLen), RetainParent|ChangeLocality|MakeDefault, 0, - DPE_SIMULATOR_OTHER_LOCALITY) + currentLocality+1) if err == nil { t.Fatalf("[FATAL]: Error while retaining parent handle and making it default in non-default context: %s", err) } else if !errors.Is(err, StatusInvalidArgument) { @@ -240,16 +219,17 @@ func testRetainParentAndMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient // Checks whether the number of derived contexts (TCI nodes) are limited by MAX_TCI_NODES attribute of the profile func testMaxTcis(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - + defer func() { c.DestroyContext(handle, DestroyDescendants) }() + currentLocality := d.GetLocality() maxTciCount := d.GetMaxTciNodes() allowedTciNodes := int(maxTciCount) - existingTciNodeCount - for i := 0; i < allowedTciNodes; i++ { + for i := 0; i < allowedTciNodes-1; i++ { resp, err := c.DeriveChild(handle, make([]byte, digestLen), DeriveChildFlags(MakeDefault), 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY, + currentLocality, ) if err != nil { @@ -263,7 +243,7 @@ func testMaxTcis(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHa make([]byte, digestLen), DeriveChildFlags(MakeDefault), 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY, + currentLocality, ) if err == nil { diff --git a/verification/verification.go b/verification/verification.go index c5d10415..5b6b77fd 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -77,7 +77,7 @@ var SignSimulationTestCase = TestCase{ "SignSimulation", TestSignSimulation, []string{"Simulation"}, } var DeriveChildTestCase = TestCase{ - "AutoInit", TestDeriveChild, []string{"AutoInit", "InternalDice", "InternalInfo"}, + "DeriveChild", TestDeriveChild, []string{"AutoInit"}, } var AllTestCases = []TestCase{ @@ -91,12 +91,12 @@ var AllTestCases = []TestCase{ SignAsymmetricTestCase, SignSymmetricTestCase, SignSimulationTestCase, + DeriveChildTestCase, GetProfileTestCase, InitializeContextTestCase, InitializeContextSimulationTestCase, InvalidHandleTestCase, WrongLocalityTestCase, - DeriveChildTestCase, } func RunTargetTestCases(target TestTarget, t *testing.T) { From 1bbfb0418277eb3ea574874a3dbddeaccb4e36ec Mon Sep 17 00:00:00 2001 From: hpya93 Date: Sat, 2 Dec 2023 00:42:37 +0530 Subject: [PATCH 11/17] . --- verification/abi.go | 1 + verification/certifyKey.go | 2 +- verification/deriveChild.go | 386 +++++++++++++++++++---------------- verification/simulator.go | 12 +- verification/verification.go | 6 + 5 files changed, 229 insertions(+), 178 deletions(-) diff --git a/verification/abi.go b/verification/abi.go index 63f76607..952524b3 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -8,6 +8,7 @@ import ( ) var DefaultContextHandle = ContextHandle{0} +var InvalidatedContextHandle = ContextHandle{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} const ( CmdMagic uint32 = 0x44504543 diff --git a/verification/certifyKey.go b/verification/certifyKey.go index 2e031412..8fdecf6e 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -351,7 +351,7 @@ func checkWithDerivedChildContextSimulation(d TestDPEInstance, c DPEClient, t *t t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) } // Revert locality for other tests - d.SetLocality(0) + d.SetLocality(locality) }() // Switch to simulated child context locality to issue CertifyKey command diff --git a/verification/deriveChild.go b/verification/deriveChild.go index 6b3eae3e..5fadca7b 100644 --- a/verification/deriveChild.go +++ b/verification/deriveChild.go @@ -7,16 +7,14 @@ import ( "testing" ) -var existingTciNodeCount = 0 - func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { - // A tci node is already created at time of auto-initialization - existingTciNodeCount += 1 - testDeriveChild(d, c, t) -} + var resp *DeriveChildResp -func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { - handle := getInitialContextHandle(d, c, t, false) + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() // Get digest size profile, err := GetTransportProfile(d) @@ -25,230 +23,266 @@ func testDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { } digestLen := profile.GetDigestSize() + currentLocality := d.GetLocality() + otherLocality := currentLocality + 1 - // Test child handles when MakeDefault flag is enabled/disabled - testChildHandles(t, d, c, handle, digestLen) + // Child context handle returned will be the default context handle when MakeDefault flag is set + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while creating child context handle: %s", err) + } + handle = &resp.NewContextHandle + if resp.NewContextHandle != DefaultContextHandle { + t.Fatalf("[FATAL]: Incorrect handle. Should return %v, but returned %v", DefaultContextHandle, *handle) + } - // Test enabling MakeDefault flag - testMakeDefault(t, d, c, handle, digestLen) + // When there is already a default handle, setting MakeDefault and RetainParent will cause error + // because there cannot be two default handles in a locality + if _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } - // Test child handle creation in other locality. - testMakeDefaultInNonDefaultContext(t, d, c, handle, digestLen) + // Retain parent should fail because parent handle is a default handle + // and child handle will be a non-default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } - // Test Privilege escalation - testPrivilegeEscalation(t, d, c, handle, digestLen) + // Child context handle should be a random handle when MakeDefault flag is NOT used + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), 0, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while creating child context handle: %s", err) + } + handle = &resp.NewContextHandle + if resp.NewContextHandle == DefaultContextHandle { + t.Fatalf("[FATAL]: Incorrect handle. Should return non-default handle, but returned %v", *handle) + } + if resp.ParentContextHandle != InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should be invalidated when retain parent is NOT set, but returned %v", resp.ParentContextHandle) + } - // Test for error while retaining parent handle in default context - testRetainParentInDefaultContext(t, d, c, handle, digestLen) + // Now, there is no default handle, setting RetainParent flag should succeed + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { + t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + parentHandle := resp.ParentContextHandle - // Test retention of parent handle in non default context - testRetainParentInNonDefaultContext(t, d, c, handle, digestLen) + if parentHandle == InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) + } - // Test enabling MakeDefault and RetainParent flags - testRetainParentAndMakeDefault(t, d, c, handle, digestLen) + // Create child context in other locality and make it default + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|ChangeLocality, 0, otherLocality); err != nil { + t.Errorf("[ERROR]: Error while creating child context handle in other locality: %s", err) + } + handle = &resp.NewContextHandle + if resp.NewContextHandle != DefaultContextHandle { + t.Fatalf("[FATAL]: Incorrect handle. Should return default handle, but returned %v", *handle) + } - // Test derive child contexts count limited by MAX_TCI_NODES supported by the profile - testMaxTcis(t, d, c, handle, digestLen) - getInitialContextHandle(d, c, t, false) -} + // Finally, restore locality of handle for other tests + prevLocality := currentLocality + d.SetLocality(otherLocality) -// Check handle of default and non-default child -func testChildHandles(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - // MakeDefault flag is not set - currentLocality := d.GetLocality() - r, err := c.DeriveChild(handle, - make([]byte, digestLen), - ChangeLocality, - 0, - currentLocality+1) + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), ChangeLocality, 0, prevLocality); err != nil { + t.Fatalf("[FATAL]: Error while creating child context handle in previous locality: %s", err) + } + handle = &resp.NewContextHandle + d.SetLocality(prevLocality) + + // Remove unwanted handles + if err = c.DestroyContext(handle, DestroyDescendants); err != nil { + t.Errorf("[ERROR]: Error while destroying unwanted child context handles: %s", err) + } + // Restore default handle + handle, err = c.RotateContextHandle(&parentHandle, RotateContextHandleFlags(TargetIsDefault)) if err != nil { - t.Fatalf("[FATAL]: Error while creating non-default child context handle: %s", err) + t.Errorf("[ERROR]: Error while restoring parent context handle as default context handle, this may cause failure in subsequent tests: %s", err) } - if r.NewContextHandle == DefaultContextHandle { - t.Errorf("[ERROR]: Incorrect handle. Should return random handle, but returned %q", &DefaultContextHandle) + // Internal input flags + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputDice, 0, 0); err != nil { + t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) } + handle = &resp.NewContextHandle - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputInfo, 0, 0); err != nil { + t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle - // MakeDefault flag is set - d.SetLocality(currentLocality + 1) - defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) - r, err = c.DeriveChild(&r.NewContextHandle, + // Privilege escalation of child + // Adding new privileges to child that parent does NOT possess will cause failure + _, err = c.DeriveChild(handle, make([]byte, digestLen), - MakeDefault|ChangeLocality, - 0, - currentLocality, - ) - - if err != nil { - t.Fatalf("[FATAL]: Error while creating default child context: %s", err) + DeriveChildFlags(InputAllowX509|InputAllowCA), + 0, 0) + if err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } - if r.NewContextHandle != DefaultContextHandle { - t.Errorf("[ERROR]: Incorrect handle. Should return %q, but returned %q", DefaultContextHandle, r.NewContextHandle) + // Privilege escalation for commands run in child context + // Similarly, when commands like CertifyKey try to make use of features that are unsupported + // by child context, it will fail. + if _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyAddIsCA); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } - - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 } -// Checks whether the new context handle could be made the default handle by -// setting MakeDefault flag in default context. -func testMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - resp, err := c.DeriveChild(handle, - make([]byte, digestLen), - MakeDefault, - 0, - DPE_SIMULATOR_AUTO_INIT_LOCALITY) +// Checks whether the number of derived contexts (TCI nodes) are limited by MAX_TCI_NODES attribute of the profile +func TestMaxTCIs(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { c.DestroyContext(handle, DestroyDescendants) }() + + // Get digest size + profile, err := GetTransportProfile(d) if err != nil { - t.Fatalf("[FATAL]: Error while setting child handle as default: %s", err) + t.Fatalf("Could not get profile: %v", err) } + digestSize := profile.GetDigestSize() - if resp.NewContextHandle != DefaultContextHandle { - t.Errorf("[FATAL]: The child handle is not set as default handle despite enabling MakeDefault flag: %s", err) + // Get Max TCI count + maxTciCount := int(d.GetMaxTciNodes()) + allowedTciCount := maxTciCount - 1 // since, a TCI node is already auto-initialized + for i := 0; i < allowedTciCount; i++ { + resp, err = c.DeriveChild(handle, make([]byte, digestSize), 0, 0, 0) + if err != nil { + t.Fatalf("[FATAL]: Error encountered in executing derive child: %v", err) + } + handle = &resp.NewContextHandle } - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 + // Exceed the Max TCI node count limit + _, err = c.DeriveChild(handle, make([]byte, digestSize), 0, 0, 0) + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusMaxTCIs) + } else if !errors.Is(err, StatusMaxTCIs) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusMaxTCIs, err) + } } -// Checks default child handle creation in other locality. -func testMakeDefaultInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { +func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp - currentLocality := d.GetLocality() - r, err := c.DeriveChild(handle, - make([]byte, digestLen), - MakeDefault|ChangeLocality, - 0, - currentLocality+1, - ) + simulation := true + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() + // Get digest size + profile, err := GetTransportProfile(d) if err != nil { - t.Fatalf("[FATAL]: Error while creating default child handle in non-default context: %s", err) + t.Fatalf("Could not get profile: %v", err) } - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 + digestLen := profile.GetDigestSize() + locality := d.GetLocality() - // Revert hardware locality and handle for further tests - d.SetLocality(currentLocality + 1) - defer d.SetLocality(currentLocality) + // MakeDefault should fail because parent handle is a non-default handle + // and child handle will be a default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } - _, err = c.DeriveChild(&r.NewContextHandle, + // Make default child context in other locality + childCtx, err := c.DeriveChild(handle, make([]byte, digestLen), - MakeDefault|ChangeLocality, + DeriveChildFlags(ChangeLocality|RetainParent|MakeDefault), 0, - currentLocality) + locality+1) // Switch locality to derive child context from Simulation context if err != nil { - t.Fatalf("[FATAL]: Error while creating default child handle in default context: %s", err) + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 -} + handle = &childCtx.NewContextHandle + parentHandle := &childCtx.ParentContextHandle -// Checks whether the derived context does not escalate beyond the privileges of parent context. -func testPrivilegeEscalation(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - var err error - escalatedChildPrivileges := []DeriveChildFlags{InternalInputDice, InternalInputDice} - - for _, flag := range escalatedChildPrivileges { - _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|flag, 0, 0) - if err == nil { - t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusArgumentNotSupported) - } else if !errors.Is(err, StatusArgumentNotSupported) { - t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusArgumentNotSupported, err) + // Clean up parent context + defer func() { + err := c.DestroyContext(parentHandle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) } - } -} + }() -// Checks whether default context does not retain parent handle. -// This is because mixture of default and non-default handles are not allowed in this context. -// Parent handle is invalidated in default context. -func testRetainParentInDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - currentLocality := d.GetLocality() - _, err := c.DeriveChild(handle, - make([]byte, digestLen), - RetainParent, - 0, - currentLocality) - if err == nil { - t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusInvalidArgument) + // Switch to simulated child context locality to issue CertifyKey command + d.SetLocality(locality + 1) + + defer func() { + // Clean up contexts after test + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) + } + // Revert locality for other tests + d.SetLocality(locality) + }() + + // Retain parent should fail because parent handle is a default handle + // and child handle will be a non-default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) } else if !errors.Is(err, StatusInvalidArgument) { - t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } -} -// Checks whether parent handle could be retained in a locality with non-default context. -func testRetainParentInNonDefaultContext(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - currentLocality := d.GetLocality() - _, err := c.DeriveChild(handle, - make([]byte, digestLen), - RetainParent|ChangeLocality, - 0, - currentLocality+1) - if err != nil { - t.Fatalf("[FATAL]: Error while retaining parent handle in non-default context: %s", err) + // Internal input flags + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputDice, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) } + handle = &resp.NewContextHandle - // Increment TCI node count, this is will be used in validating maximum allowed TCI nodes. - existingTciNodeCount += 1 -} - -// Checks whether error is returned when RetainParent and MakeDefault flags are used together in presence of -// default context handle. This should fail because RetainParent flag and MakeDefault when used together -// tries to create two default context handles in the locality which is not allowed since a locality can have -// only one default context handle. -func testRetainParentAndMakeDefault(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - currentLocality := d.GetLocality() - _, err := c.DeriveChild(handle, - make([]byte, digestLen), - RetainParent|ChangeLocality|MakeDefault, - 0, - currentLocality+1) - if err == nil { - t.Fatalf("[FATAL]: Error while retaining parent handle and making it default in non-default context: %s", err) - } else if !errors.Is(err, StatusInvalidArgument) { - t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputInfo, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) } -} + handle = &resp.NewContextHandle -// Checks whether the number of derived contexts (TCI nodes) are limited by MAX_TCI_NODES attribute of the profile -func testMaxTcis(t *testing.T, d TestDPEInstance, c DPEClient, handle *ContextHandle, digestLen int) { - defer func() { c.DestroyContext(handle, DestroyDescendants) }() - currentLocality := d.GetLocality() - maxTciCount := d.GetMaxTciNodes() - allowedTciNodes := int(maxTciCount) - existingTciNodeCount - - for i := 0; i < allowedTciNodes-1; i++ { - resp, err := c.DeriveChild(handle, - make([]byte, digestLen), - DeriveChildFlags(MakeDefault), - 0, - currentLocality, - ) + // Setting RetainParent flag should not invalidate the parent handle + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { + t.Fatalf("[FATAL]: Error while making child context and retaining parent handle %s", err) + } + handle = &resp.NewContextHandle - if err != nil { - t.Fatalf("[FATAL]: Error encountered in executing derive child: %v", err) - } - handle = &resp.NewContextHandle + if resp.ParentContextHandle == InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) } - // Exceed the Max TCI node count limit - _, err := c.DeriveChild(handle, + // Privilege escalation of child + // Adding new privileges to child that parent does NOT possess will cause failure + _, err = c.DeriveChild(handle, make([]byte, digestLen), - DeriveChildFlags(MakeDefault), - 0, - currentLocality, - ) - + DeriveChildFlags(InputAllowX509|InputAllowCA), + 0, 0) if err == nil { - t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusMaxTCIs) - } else if !errors.Is(err, StatusMaxTCIs) { - t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusMaxTCIs, err) + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Privilege escalation for commands run in child context + // Similarly, when commands like CertifyKey try to make use of features that are unsupported + // by child context, it will fail. + if _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyAddIsCA); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } } diff --git a/verification/simulator.go b/verification/simulator.go index 991ced9e..b06b0395 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -231,9 +231,19 @@ func GetSimulatorTargets() []TestTarget { }, { "DefaultSupport", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric", "InternalDice", "InternalInfo"}), AllTestCases, }, + { + "DeriveChild_MaxTCIs", + getTestTarget([]string{"AutoInit", "Simulation"}), + []TestCase{DeriveChildMaxTCIsTestCase}, + }, + { + "DeriveChild_Simulation", + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric", "InternalDice", "InternalInfo"}), + []TestCase{DeriveChildSimulationTestCase}, + }, { "CertifyKey_WithoutExtendTci", getTestTarget([]string{"AutoInit", "X509"}), diff --git a/verification/verification.go b/verification/verification.go index 5b6b77fd..b3fe1aaa 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -79,6 +79,12 @@ var SignSimulationTestCase = TestCase{ var DeriveChildTestCase = TestCase{ "DeriveChild", TestDeriveChild, []string{"AutoInit"}, } +var DeriveChildSimulationTestCase = TestCase{ + "DeriveChildSimulation", TestDeriveChildSimulation, []string{"AutoInit", "Simulation"}, +} +var DeriveChildMaxTCIsTestCase = TestCase{ + "DeriveChild_MaxTCIs", TestMaxTCIs, []string{"AutoInit"}, +} var AllTestCases = []TestCase{ CertifyKeyTestCase, From c17fe5449d31b28c29547d59fd6249c8e1359cd1 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Fri, 15 Dec 2023 22:08:33 +0530 Subject: [PATCH 12/17] . --- verification/certifyKey.go | 2 +- verification/certs.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/verification/certifyKey.go b/verification/certifyKey.go index 2b187d60..daf0a62e 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -702,4 +702,4 @@ func checkCertifyKeyBasicConstraints(t *testing.T, extensions []pkix.Extension, if flagIsCA != bc.IsCA { t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, bc.IsCA) } -} \ No newline at end of file +} diff --git a/verification/certs.go b/verification/certs.go index b741e982..d26d34f6 100644 --- a/verification/certs.go +++ b/verification/certs.go @@ -519,4 +519,4 @@ func validateDiceTcbFwids(leafCertBytes []byte, currentTcis [][]byte, digestLen verifyDiceTcbDigest(tcbinfo, wantCurrentTci, lastCumulativeTCI) } return err -} \ No newline at end of file +} From 04826b2a0052007b2703695c21b0620c8e235eee Mon Sep 17 00:00:00 2001 From: hpya93 Date: Sat, 16 Dec 2023 19:27:00 +0530 Subject: [PATCH 13/17] . --- Cargo.lock | 161 +++++++++++++++++++++++++ dpe/fuzz/Cargo.lock | 74 ++++++++++++ verification/certifyKey.go | 226 +++++------------------------------ verification/deriveChild.go | 144 +++++++++++++--------- verification/go.mod | 2 +- verification/simulator.go | 36 ++++-- verification/verification.go | 27 +++-- 7 files changed, 401 insertions(+), 269 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81df4f30..b9d7d82c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,6 +134,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.5" @@ -275,15 +281,33 @@ name = "crypto" version = "0.1.0" dependencies = [ "arrayvec", + "base64ct", + "ecdsa", "hkdf", + "hmac", "openssl", + "p256", + "p384", "rand", + "sec1", "sha2", "strum", "strum_macros", "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -364,6 +388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -398,6 +423,41 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "env_logger" version = "0.10.1" @@ -421,6 +481,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "flagset" version = "0.4.4" @@ -450,6 +520,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -463,6 +534,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "heck" version = "0.4.1" @@ -656,6 +738,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "pem" version = "2.0.1" @@ -675,6 +781,16 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -685,8 +801,10 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "cfg-if", "openssl", "ufmt", + "x509-cert", ] [[package]] @@ -701,6 +819,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -778,6 +905,16 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -806,6 +943,20 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "serde" version = "1.0.192" @@ -837,6 +988,16 @@ dependencies = [ "digest", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simulator" version = "0.1.0" diff --git a/dpe/fuzz/Cargo.lock b/dpe/fuzz/Cargo.lock index 83059472..f4b163fc 100644 --- a/dpe/fuzz/Cargo.lock +++ b/dpe/fuzz/Cargo.lock @@ -80,6 +80,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -156,6 +162,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -192,6 +204,30 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "deranged" version = "0.3.8" @@ -262,6 +298,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +[[package]] +name = "flagset" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" + [[package]] name = "foreign-types" version = "0.3.2" @@ -417,6 +459,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -427,8 +478,10 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "cfg-if", "openssl", "ufmt", + "x509-cert", ] [[package]] @@ -528,6 +581,16 @@ dependencies = [ "time", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.10.0" @@ -765,6 +828,17 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "x509-cert" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eefca1d99701da3a57feb07e5079fc62abba059fc139e98c13bbb250f3ef29" +dependencies = [ + "const-oid", + "der", + "spki", +] + [[package]] name = "xdg" version = "2.5.2" diff --git a/verification/certifyKey.go b/verification/certifyKey.go index daf0a62e..fb149027 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -36,46 +36,12 @@ func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { testCertifyKey(d, c, t, true) } -// Checks whether FWID array omits index-1 when extend TCI is not supported in DPE profile. -func TestCertifyKeyWithoutExtendTciSupport(d TestDPEInstance, c DPEClient, t *testing.T) { - simulation := false - handle := getInitialContextHandle(d, c, t, simulation) - - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - // Get DPE leaf certificate from CertifyKey - certifiedKey, err := c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyKeyFlags(0)) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) - } - - leafCertBytes := certifiedKey.Certificate - var leafCert *x509.Certificate - - if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { - t.Errorf("[ERROR]: Could not parse leaf certificate %s", err) - } - - multiTcbInfo, err := getMultiTcbInfo(leafCert.Extensions) - if err != nil { - t.Errorf("[ERROR]: Could not parse multi TCB information: extension %s", err) - } - - if len(multiTcbInfo) == 0 { - t.Errorf("[ERROR]: Certificate MutliTcbInfo is empty") - } +func TestDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T) { + testDiceTcbInfo(d, c, t, false) +} - // Check whether fwids array has only fwids[0] i.e, TCI_CURRENT measurement - // and TCI_CUMULATIVE i.e fwids[1] is omitted in every Dice TCB info block - for i, tcbinfo := range multiTcbInfo { - if len(tcbinfo.Fwids) != 1 { - t.Errorf("Extend TCI is not supported by profile, expected FWIDs length in block-%d is %d but got %d", i, 1, len(tcbinfo.Fwids)) - } - } +func TestDiceTcbInfoSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + testDiceTcbInfo(d, c, t, true) } func TestCertifyKey_Csr(d TestDPEInstance, c DPEClient, t *testing.T) { @@ -216,26 +182,35 @@ func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation boo t.Errorf("[ERROR]: %v", err) } + _, err = getMultiTcbInfo(leafCert.Extensions) + if err != nil { + t.Errorf("[ERROR]: Could not parse multi TCB information: extension %s", err) + } + // Reassign handle for simulation mode. // However, this does not impact in default mode because // same default context handle is returned in default mode. handle = &certifyKeyResp.Handle } - // DeriveChild to add more TCIs and call CertifyKey again. - if simulation { - handle = checkWithDerivedChildContextSimulation(d, c, t, handle) - } else { - checkWithDerivedChildContext(d, c, t, handle) - } } -// Checks Multi Tcb Info for context derived from non-simulation mode -// Check CertifyKey command after adding more TCIs by DeriveChild command. -// The MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. +// Checks Multi Tcb Info for context derived from non-simulation mode by adding more TCIs by DeriveChild command. +// MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. // In a DiceTcbInfo block of a given TCI node, // - the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. // - the "fwid" field must contain cumulative TCI measurement. -func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) { +func testDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { + handle := getInitialContextHandle(d, c, t, simulation) + if simulation { + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() + } + profile, err := GetTransportProfile(d) if err != nil { t.Fatalf("Could not get profile: %v", err) @@ -254,27 +229,13 @@ func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, childTCI1[i] = byte(i + 1) } - // Set tciType to verify in multiTcbInfo extension + // Set tciType to verify in UEID extension tciType := uint32(2) - // Preserve parent context to restore for subsequent tests - parentHandle, err := c.RotateContextHandle(handle, RotateContextHandleFlags(0)) - if err != nil { - t.Errorf("[ERROR]: Error while rotating parent context handle, this may cause failure in subsequent tests: %s", err) - } - - // Deferred call to restore default context handle for subsequent tests - defer func() { - _, err = c.RotateContextHandle(parentHandle, RotateContextHandleFlags(TargetIsDefault)) - if err != nil { - t.Errorf("[ERROR]: Error while restoring parent context handle as default context handle, this may cause failure in subsequent tests: %s", err) - } - }() - // Derive Child context with input data, tag it and check TCI_CUMULATIVE - childCtx, err := c.DeriveChild(parentHandle, + childCtx, err := c.DeriveChild(handle, childTCI1, - DeriveChildFlags(InputAllowX509|RetainParent), + DeriveChildFlags(InputAllowX509), tciType, 0) @@ -282,19 +243,10 @@ func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - childHandle := &childCtx.NewContextHandle - parentHandle = &childCtx.ParentContextHandle - - // Clean up contexts - defer func() { - err := c.DestroyContext(childHandle, DestroyDescendants) - if err != nil { - t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) - } - }() + handle = &childCtx.NewContextHandle var childTcbInfo DiceTcbInfo - childHandle, childTcbInfo, err = getTcbInfoForHandle(c, childHandle) + handle, childTcbInfo, err = getTcbInfoForHandle(c, handle) if err != nil { t.Fatalf("[FATAL]: Could not get TcbInfo: %v", err) } @@ -327,7 +279,7 @@ func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, childTCI2[i] = byte(i + 2) } - childCtx, err = c.DeriveChild(childHandle, + childCtx, err = c.DeriveChild(handle, childTCI2, DeriveChildFlags(InputAllowX509), tciType, @@ -337,15 +289,15 @@ func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - childHandle = &childCtx.NewContextHandle + handle = &childCtx.NewContextHandle // Get latest TCB information - certifiedKey, err := c.CertifyKey(childHandle, childTCI2, CertifyKeyX509, 0) + certifiedKey, err := c.CertifyKey(handle, childTCI2, CertifyKeyX509, 0) if err != nil { t.Fatalf("[FATAL]: Could not certify key: %s", err) } - childHandle = &certifiedKey.Handle + handle = &certifiedKey.Handle leafCertBytes := certifiedKey.Certificate // Build list of tci_current for validation and use it for validating TCI measurements @@ -355,118 +307,6 @@ func checkWithDerivedChildContext(d TestDPEInstance, c DPEClient, t *testing.T, } } -// Checks Multi Tcb Info for context derived from simulation mode -func checkWithDerivedChildContextSimulation(d TestDPEInstance, c DPEClient, t *testing.T, handle *ContextHandle) *ContextHandle { - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - var hashAlg asn1.ObjectIdentifier - if digestLen == 32 { - hashAlg = OidSHA256 - } else if digestLen == 48 { - hashAlg = OidSHA384 - } - - childTCI := make([]byte, digestLen) - for i := range childTCI { - childTCI[i] = byte(i) - } - - // Set tciType to verify in UEID extension - tciType := uint32(2) - - locality := d.GetLocality() - - // Derive Child context with input data, tag it and check TCI_CUMULATIVE - childCtx, err := c.DeriveChild(handle, - childTCI, - DeriveChildFlags(InputAllowX509|ChangeLocality|RetainParent), - tciType, - locality+1) // Switch locality to derive child context from Simulation context - - if err != nil { - t.Fatalf("[FATAL]: Error while creating child handle: %s", err) - } - - handle = &childCtx.NewContextHandle - parentHandle := &childCtx.ParentContextHandle - - // Clean up contexts - defer func() { - err := c.DestroyContext(handle, DestroyDescendants) - if err != nil { - t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) - } - // Revert locality for other tests - d.SetLocality(0) - }() - - // Switch to simulated child context locality to issue CertifyKey command - d.SetLocality(locality + 1) - - // Make CertifyKey call and get current MultiTcbInfo - var leafCert *x509.Certificate - - certifiedKey, err := c.CertifyKey(handle, childTCI, CertifyKeyX509, 0) - if err != nil { - t.Errorf("[ERROR]: Could not certify key: %s", err) - } - - handle = &certifiedKey.Handle // Update handle - leafCertBytes := certifiedKey.Certificate - - if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { - t.Errorf("[ERROR]: Could not parse certificate: %s", err) - } - - multiTcbInfo, err := getMultiTcbInfo(leafCert.Extensions) - if err != nil { - t.Errorf("[ERROR]: Could not parse multi TCB info extension: %s", err) - } - - if len(multiTcbInfo) == 0 { - t.Errorf("[ERROR]: Certificate MutliTcbInfo is empty") - } - - childTcbInfo := multiTcbInfo[0] - if !bytes.Equal(childTcbInfo.Fwids[0].Digest, childTCI) { - t.Errorf("[ERROR]: Got current TCI %x, expected %x", childTcbInfo.Fwids[0].Digest, childTCI) - } - - // Preform checks on multi Tcb info of child TCI node - // Check vendorInfo field - if err = checkDiceTcbVendorInfo(childTcbInfo, d.GetLocality()); err != nil { - t.Errorf("[ERROR]: %v", err) - } - - // Check type field - if err = checkCurrentDiceTcbTciType(childTcbInfo, tciType); err != nil { - t.Errorf("[ERROR]: %v", err) - } - - // Check hash algorithm - if err = checkDiceTcbHashAlgorithm(childTcbInfo, hashAlg); err != nil { - t.Errorf("[ERROR]: %v", err) - } - - // Extend TCI support is mandatory for this validation - if !d.GetSupport().ExtendTci { - t.Errorf("ExtendTCI is unsupported by profile, unable to run tests to verify TCI_CUMULATIVE measurements") - return parentHandle - } - - // Check all dice tcb measurements - // Build list of tci_current for validation - currentTCIs := [][]byte{childTCI} - if err = validateDiceTcbFwids(certifiedKey.Certificate, currentTCIs, digestLen); err != nil { - t.Errorf("[ERROR]: %v", err) - } - return parentHandle -} - func checkPubKey(t *testing.T, p Profile, pubkey any, response CertifiedKey) { var pubKeyInResponse ecdsa.PublicKey switch p { diff --git a/verification/deriveChild.go b/verification/deriveChild.go index 5fadca7b..255df15d 100644 --- a/verification/deriveChild.go +++ b/verification/deriveChild.go @@ -23,8 +23,6 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { } digestLen := profile.GetDigestSize() - currentLocality := d.GetLocality() - otherLocality := currentLocality + 1 // Child context handle returned will be the default context handle when MakeDefault flag is set if resp, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault, 0, 0); err != nil { @@ -66,7 +64,7 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { // Now, there is no default handle, setting RetainParent flag should succeed if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { - t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) } handle = &resp.NewContextHandle parentHandle := resp.ParentContextHandle @@ -74,17 +72,41 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { if parentHandle == InvalidatedContextHandle { t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) } +} - // Create child context in other locality and make it default - if resp, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|ChangeLocality, 0, otherLocality); err != nil { - t.Errorf("[ERROR]: Error while creating child context handle in other locality: %s", err) +func TestChangeLocality(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) } - handle = &resp.NewContextHandle - if resp.NewContextHandle != DefaultContextHandle { - t.Fatalf("[FATAL]: Incorrect handle. Should return default handle, but returned %v", *handle) + + if !d.HasLocalityControl() { + t.Skip("WARNING: DPE profile does not have control over locality. Skipping this test...") } - // Finally, restore locality of handle for other tests + digestLen := profile.GetDigestSize() + currentLocality := d.GetLocality() + otherLocality := currentLocality + 1 + + // Create child context in other locality + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), ChangeLocality, 0, otherLocality); err != nil { + t.Fatalf("[ERROR]: Error while creating child context handle in other locality: %s", err) + } + handle = &resp.NewContextHandle + + // Revert to same locality from other locality prevLocality := currentLocality d.SetLocality(otherLocality) @@ -93,30 +115,70 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { } handle = &resp.NewContextHandle d.SetLocality(prevLocality) +} - // Remove unwanted handles - if err = c.DestroyContext(handle, DestroyDescendants); err != nil { - t.Errorf("[ERROR]: Error while destroying unwanted child context handles: %s", err) - } +// Checks whether the DeriveChild input flags - InternalDiceInfo, InternalInputInfo are supported +// while creating child contexts when these features are supported in DPE profile. +func TestInternalInputFlags(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() - // Restore default handle - handle, err = c.RotateContextHandle(&parentHandle, RotateContextHandleFlags(TargetIsDefault)) + // Get digest size + profile, err := GetTransportProfile(d) if err != nil { - t.Errorf("[ERROR]: Error while restoring parent context handle as default context handle, this may cause failure in subsequent tests: %s", err) + t.Fatalf("Could not get profile: %v", err) } + digestLen := profile.GetDigestSize() // Internal input flags - if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputDice, 0, 0); err != nil { - t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) + if d.GetSupport().InternalDice { + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), DeriveChildFlags(InternalInputDice), 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + } else { + t.Skip("[WARNING]: Profile has no support for \"InternalInputDice\" flag. Skipping the validation for this flag...") } - handle = &resp.NewContextHandle - if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputInfo, 0, 0); err != nil { - t.Errorf("[Error]: Error while making child context handle as default handle: %s", err) + if d.GetSupport().InternalInfo { + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), DeriveChildFlags(InternalInputInfo), 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + } else { + t.Skip("[WARNING]: Profile has no support for \"InternalInputInfo\" flag. Skipping the validation for this flag...") + } +} + +// Checks the privilege escalation of child +// When commands try to make use of features that are unsupported by child context, they fail. +func TestPrivilegesEscalation(d TestDPEInstance, c DPEClient, t *testing.T) { + var err error + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + + // Create a child TCI node with no special privileges + resp, err := c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(0), + 0, 0) + if err != nil { + t.Fatalf("[FATAL]: Error encountered in getting child context: %v", err) } handle = &resp.NewContextHandle - // Privilege escalation of child // Adding new privileges to child that parent does NOT possess will cause failure _, err = c.DeriveChild(handle, make([]byte, digestLen), @@ -128,8 +190,7 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } - // Privilege escalation for commands run in child context - // Similarly, when commands like CertifyKey try to make use of features that are unsupported + // Similarly, when commands like CertifyKey try to make use of features/flags that are unsupported // by child context, it will fail. if _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyAddIsCA); err == nil { t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) @@ -222,7 +283,6 @@ func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { } }() - // Switch to simulated child context locality to issue CertifyKey command d.SetLocality(locality + 1) defer func() { @@ -244,17 +304,6 @@ func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) } - // Internal input flags - if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputDice, 0, 0); err != nil { - t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) - } - handle = &resp.NewContextHandle - - if resp, err = c.DeriveChild(handle, make([]byte, digestLen), InternalInputInfo, 0, 0); err != nil { - t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) - } - handle = &resp.NewContextHandle - // Setting RetainParent flag should not invalidate the parent handle if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { t.Fatalf("[FATAL]: Error while making child context and retaining parent handle %s", err) @@ -264,25 +313,4 @@ func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { if resp.ParentContextHandle == InvalidatedContextHandle { t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) } - - // Privilege escalation of child - // Adding new privileges to child that parent does NOT possess will cause failure - _, err = c.DeriveChild(handle, - make([]byte, digestLen), - DeriveChildFlags(InputAllowX509|InputAllowCA), - 0, 0) - if err == nil { - t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) - } else if !errors.Is(err, StatusInvalidArgument) { - t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) - } - - // Privilege escalation for commands run in child context - // Similarly, when commands like CertifyKey try to make use of features that are unsupported - // by child context, it will fail. - if _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyAddIsCA); err == nil { - t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) - } else if !errors.Is(err, StatusInvalidArgument) { - t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) - } } diff --git a/verification/go.mod b/verification/go.mod index 04eb612b..e3a7eccb 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -25,4 +25,4 @@ require ( golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.11.0 // indirect google.golang.org/protobuf v1.31.0 // indirect -) \ No newline at end of file +) diff --git a/verification/simulator.go b/verification/simulator.go index b06b0395..e13d153d 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -231,23 +231,43 @@ func GetSimulatorTargets() []TestTarget { }, { "DefaultSupport", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric", "InternalDice", "InternalInfo"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "IsSymmetric", "ExtendTci"}), AllTestCases, }, { - "DeriveChild_MaxTCIs", - getTestTarget([]string{"AutoInit", "Simulation"}), - []TestCase{DeriveChildMaxTCIsTestCase}, + "CertifyKey_TcbValidation", + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci"}), + []TestCase{DiceTcbValidationTestCase, TcbValidationSimulationTestCase}, + }, + { + "DeriveChild", + getTestTarget([]string{"AutoInit", "X509", "IsCA"}), + []TestCase{DeriveChildTestCase}, }, { "DeriveChild_Simulation", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric", "InternalDice", "InternalInfo"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "IsCA"}), []TestCase{DeriveChildSimulationTestCase}, }, { - "CertifyKey_WithoutExtendTci", - getTestTarget([]string{"AutoInit", "X509"}), - []TestCase{CertifyKeyWithoutExtendTciTestCase}, + "DeriveChild_PrivilegeEscalation", + getTestTarget([]string{"AutoInit", "X509", "IsCA"}), + []TestCase{DeriveChildPrivilegeEscalationTestCase}, + }, + { + "DeriveChild_InputFlags", + getTestTarget([]string{"AutoInit", "Simulation", "InternalDice", "InternalInfo"}), + []TestCase{DeriveChildInputFlagsTestCase}, + }, + { + "DeriveChild_MaxTCIs", + getTestTarget([]string{"AutoInit", "Simulation"}), + []TestCase{DeriveChildMaxTCIsTestCase}, + }, + { + "DeriveChild_ChangeLocality", + getTestTarget([]string{"AutoInit", "Simulation"}), + []TestCase{DeriveChildLocalityTestCase}, }, { "GetProfile_Simulation", diff --git a/verification/verification.go b/verification/verification.go index 54918ba0..a53101a1 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -26,19 +26,20 @@ var InitializeContextTestCase = TestCase{ var InitializeContextSimulationTestCase = TestCase{ "InitializeContextSimulation", TestInitializeSimulation, []string{"Simulation"}, } - -// ExtendTci is required for tci_cumulative in fwid, RotateContext handle for restore parent context after using child context var CertifyKeyTestCase = TestCase{ - "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, + "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA", "RotateContext"}, +} +var CertifyKeySimulationTestCase = TestCase{ + "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext"}, } var CertifyKeyCsrTestCase = TestCase{ "CertifyKeyCsr", TestCertifyKey_Csr, []string{"AutoInit", "Csr", "IsCA"}, } -var CertifyKeySimulationTestCase = TestCase{ - "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, +var DiceTcbValidationTestCase = TestCase{ + "CheckDiceTcbInfo", TestDiceTcbInfo, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, } -var CertifyKeyWithoutExtendTciTestCase = TestCase{ - "CertifyKeyWithoutExtendTciSupport", TestCertifyKeyWithoutExtendTciSupport, []string{"AutoInit", "X509"}, +var TcbValidationSimulationTestCase = TestCase{ + "CheckDiceTcbInfoInSimulationMode", TestDiceTcbInfoSimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, } var GetCertificateChainTestCase = TestCase{ "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, @@ -83,11 +84,20 @@ var DeriveChildTestCase = TestCase{ "DeriveChild", TestDeriveChild, []string{"AutoInit"}, } var DeriveChildSimulationTestCase = TestCase{ - "DeriveChildSimulation", TestDeriveChildSimulation, []string{"AutoInit", "Simulation"}, + "DeriveChildSimulation", TestDeriveChildSimulation, []string{"AutoInit", "Simulation", "X509", "InternalDice", "InternalInfo"}, } var DeriveChildMaxTCIsTestCase = TestCase{ "DeriveChild_MaxTCIs", TestMaxTCIs, []string{"AutoInit"}, } +var DeriveChildLocalityTestCase = TestCase{ + "DeriveChild_ChangeLocality", TestChangeLocality, []string{"AutoInit"}, +} +var DeriveChildPrivilegeEscalationTestCase = TestCase{ + "DeriveChild_PrivilegeEscalation", TestPrivilegesEscalation, []string{"AutoInit", "X509", "IsCA"}, +} +var DeriveChildInputFlagsTestCase = TestCase{ + "DeriveChild_InputFlagsSupport", TestInternalInputFlags, []string{"AutoInit", "InternalDice", "InternalInfo"}, +} var TpmPolicySigningTestCase = TestCase{ "TPMPolicySigning", TestTpmPolicySigning, []string{"AutoInit", "X509"}, } @@ -105,7 +115,6 @@ var AllTestCases = []TestCase{ SignAsymmetricTestCase, SignSymmetricTestCase, SignSimulationTestCase, - DeriveChildTestCase, GetProfileTestCase, InitializeContextTestCase, InitializeContextSimulationTestCase, From 76fe4aa86b0227e3e6818cca0ee7b483fd2e3029 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Sat, 16 Dec 2023 19:53:22 +0530 Subject: [PATCH 14/17] . --- verification/deriveChild.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/verification/deriveChild.go b/verification/deriveChild.go index 255df15d..d920288d 100644 --- a/verification/deriveChild.go +++ b/verification/deriveChild.go @@ -74,7 +74,12 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { } } +// Validates DerivedChild command with ChangeLocality flag. func TestChangeLocality(d TestDPEInstance, c DPEClient, t *testing.T) { + if !d.HasLocalityControl() { + t.Skip("WARNING: DPE profile does not have control over locality. Skipping this test...") + } + var resp *DeriveChildResp simulation := false handle := getInitialContextHandle(d, c, t, simulation) @@ -92,10 +97,6 @@ func TestChangeLocality(d TestDPEInstance, c DPEClient, t *testing.T) { t.Fatalf("Could not get profile: %v", err) } - if !d.HasLocalityControl() { - t.Skip("WARNING: DPE profile does not have control over locality. Skipping this test...") - } - digestLen := profile.GetDigestSize() currentLocality := d.GetLocality() otherLocality := currentLocality + 1 @@ -235,6 +236,9 @@ func TestMaxTCIs(d TestDPEInstance, c DPEClient, t *testing.T) { } func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + if !d.HasLocalityControl() { + t.Skip("WARNING: DPE profile does not have control over locality, DeriveContext in Simulation mode cannot be tested without this support. Skipping this test...") + } var resp *DeriveChildResp simulation := true From 00cd41244530fde8eacb3899b9b78c14618b7e38 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 19 Dec 2023 22:58:11 +0530 Subject: [PATCH 15/17] . --- verification/simulator.go | 4 ++-- verification/verification.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/verification/simulator.go b/verification/simulator.go index e13d153d..d919bbc8 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -231,13 +231,13 @@ func GetSimulatorTargets() []TestTarget { }, { "DefaultSupport", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "IsSymmetric", "ExtendTci"}), + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), AllTestCases, }, { "CertifyKey_TcbValidation", getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci"}), - []TestCase{DiceTcbValidationTestCase, TcbValidationSimulationTestCase}, + []TestCase{DiceTcbValidationTestCase, DiceTcbValidationSimulationTestCase}, }, { "DeriveChild", diff --git a/verification/verification.go b/verification/verification.go index a53101a1..f00d0eb4 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -38,7 +38,7 @@ var CertifyKeyCsrTestCase = TestCase{ var DiceTcbValidationTestCase = TestCase{ "CheckDiceTcbInfo", TestDiceTcbInfo, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, } -var TcbValidationSimulationTestCase = TestCase{ +var DiceTcbValidationSimulationTestCase = TestCase{ "CheckDiceTcbInfoInSimulationMode", TestDiceTcbInfoSimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, } var GetCertificateChainTestCase = TestCase{ From cbe73f7c8a8a730b32ed3b4b5621adf110f5343e Mon Sep 17 00:00:00 2001 From: hpya93 Date: Tue, 19 Dec 2023 23:15:34 +0530 Subject: [PATCH 16/17] split changes --- verification/certifyKey.go | 644 ++++++++++++++++------------ verification/certs.go | 378 +--------------- verification/extendTCI.go | 34 +- verification/getCertificateChain.go | 16 +- verification/simulator.go | 5 - verification/verification.go | 12 +- 6 files changed, 417 insertions(+), 672 deletions(-) diff --git a/verification/certifyKey.go b/verification/certifyKey.go index fb149027..99c69999 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -15,14 +15,96 @@ import ( "math/big" "reflect" "testing" + "time" "go.mozilla.org/pkcs7" zx509 "github.com/zmap/zcrypto/x509" zlint "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" + + "golang.org/x/exp/slices" +) + +var TcgDiceCriticalExtensions = [...]string{ + OidExtensionTcgDiceMultiTcbInfo.String(), + OidExtensionTcgDiceUeid.String(), +} + +var TcgDiceExtendedKeyUsages = [...]string{ + OidExtensionTcgDiceKpIdentityLoc.String(), + OidExtensionTcgDiceKpAttestLoc.String(), +} + +// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} +// +// TcgUeid ::== SEQUENCE { +// ueid OCTET STRING +// } +type TcgUeidExtension struct { + Ueid []uint8 `asn1:"ueid,implicit"` +} + +// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} +// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo +// +// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} +// +// DiceTcbInfo ::== SEQUENCE { +// vendor [0] IMPLICIT UTF8String OPTIONAL, +// model [1] IMPLICIT UTF8String OPTIONAL, +// version [2] IMPLICIT UTF8String OPTIONAL, +// svn [3] IMPLICIT INTEGER OPTIONAL, +// layer [4] IMPLICIT INTEGER OPTIONAL, +// index [5] IMPLICIT INTEGER OPTIONAL, +// fwids [6] IMPLICIT FWIDLIST OPTIONAL, +// flags [7] IMPLICIT OperationalFlags OPTIONAL, +// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, +// type [9] IMPLICIT OCTET STRING OPTIONAL, +// } +// +// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID +// FWID ::== SEQUENCE { +// hashAlg OBJECT IDENTIFIER, +// digest OCTET STRING +// } +// +// OperationalFlags ::= BIT STRING { +// notConfigured (0), +// notSecure (1), +// recovery (2), +// debug (3) +// } + +type Fwid struct { + HashAlg asn1.ObjectIdentifier + Digest []byte +} + +type DiceTcbInfo struct { + Vendor string `asn1:"optional,tag:0,utf8"` + Model string `asn1:"optional,tag:1,utf8"` + Version string `asn1:"optional,tag:2,utf8"` + SVN int `asn1:"optional,tag:3"` + Layer int `asn1:"optional,tag:4"` + Index int `asn1:"optional,tag:5"` + Fwids []Fwid `asn1:"optional,tag:6"` + Flags OperationalFlag `asn1:"optional,tag:7"` + VendorInfo []byte `asn1:"optional,tag:8"` + Type []byte `asn1:"optional,tag:9"` +} + +type OperationalFlag int + +const ( + NotConfigured OperationalFlag = iota + NotSecure + Debug + Recovery ) +type TcgMultiTcbInfo = []DiceTcbInfo + type CertifyKeyParams struct { Label []byte Flags CertifyKeyFlags @@ -36,14 +118,6 @@ func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { testCertifyKey(d, c, t, true) } -func TestDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T) { - testDiceTcbInfo(d, c, t, false) -} - -func TestDiceTcbInfoSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { - testDiceTcbInfo(d, c, t, true) -} - func TestCertifyKey_Csr(d TestDPEInstance, c DPEClient, t *testing.T) { ctx := getInitialContextHandle(d, c, t, false) @@ -120,236 +194,197 @@ func TestCertifyKey_Csr(d TestDPEInstance, c DPEClient, t *testing.T) { } } -func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { - handle := getInitialContextHandle(d, c, t, simulation) - if simulation { - // Clean up contexts - defer func() { - err := c.DestroyContext(handle, DestroyDescendants) - if err != nil { - t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) +// Ignores critical extensions that are unknown to x509 package +// but atleast defined in DPE certificate profile specification. +// UnhandledCriticalExtensions may have only custom extensions mentioned in spec +// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec. +// positive case expects the unknownExtnMap to be empty. +func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) { + t.Helper() + unknownExtnMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnhandledCriticalExtensions) > 0 { + unknownExtns := []string{} + for _, extn := range cert.UnhandledCriticalExtensions { + if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { + unknownExtns = append(unknownExtns, extn.String()) + } } - }() - } - - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - seqLabel := make([]byte, digestLen) - for i := range seqLabel { - seqLabel[i] = byte(i) - } - - certifyKeyParams := []CertifyKeyParams{ - {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, - {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(CertifyAddIsCA)}, - {Label: seqLabel, Flags: CertifyKeyFlags(0)}, - } - for _, params := range certifyKeyParams { - // Get DPE leaf certificate from CertifyKey - certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) + if len(unknownExtnMap) == 0 { + cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} + } else { + unknownExtnMap[cert.Subject.String()] = unknownExtns + } } - - // Get root and intermediate certificates to validate certificate chain of leaf cert - certChainBytes, err := c.GetCertificateChain() - if err != nil { - t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) + } + // The error details in this map will be logged + if len(unknownExtnMap) > 0 { + for certSubject, ext := range unknownExtnMap { + t.Errorf("[ERROR]: Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext) } + t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unhandled critical extensions list") + } +} - leafCertBytes := certifyKeyResp.Certificate - - // Run X.509 linter on full certificate chain and file issues for errors - leafCert := checkCertificateStructure(t, leafCertBytes) - certChain := checkCertificateChain(t, certChainBytes) - - // Check default context handle is unchanged - checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) - - // Check public key and algorithm parameters are correct - checkPubKey(t, profile, leafCert.PublicKey, *certifyKeyResp) - - // Check all extensions - checkCertifyKeyExtensions(t, leafCert.Extensions, params.Flags, params.Label) +// Ignores extended key usages that are unknown to x509 package +// but atleast defined in DPE certificate profile specification. +// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec +// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec. +// positive case expects the unknownKeyUsagesMap to be empty. +func removeTcgDiceExtendedKeyUsages(t *testing.T, certs []*x509.Certificate) { + t.Helper() + unknownKeyUsagesMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnknownExtKeyUsage) > 0 { + unknownKeyUsages := []string{} + for _, eku := range cert.UnknownExtKeyUsage { + if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { + unknownKeyUsages = append(unknownKeyUsages, eku.String()) + } + } - // Ensure full certificate chain has valid signatures - // This also checks certificate lifetime, signatures as part of cert chain validation - if err = validateLeafCertChain(certChain, leafCert); err != nil { - t.Errorf("[ERROR]: %v", err) + if len(unknownKeyUsagesMap) == 0 { + cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} + } else { + unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages + } } - - _, err = getMultiTcbInfo(leafCert.Extensions) - if err != nil { - t.Errorf("[ERROR]: Could not parse multi TCB information: extension %s", err) + } + // The error details in this map will be logged + if len(unknownKeyUsagesMap) > 0 { + for certSubject, ext := range unknownKeyUsagesMap { + t.Errorf("[ERROR]: Certificate \"%s\" has unknown extended key usages \"%s\"", certSubject, ext) } - - // Reassign handle for simulation mode. - // However, this does not impact in default mode because - // same default context handle is returned in default mode. - handle = &certifyKeyResp.Handle + t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unknown extended key usages list") } } -// Checks Multi Tcb Info for context derived from non-simulation mode by adding more TCIs by DeriveChild command. -// MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. -// In a DiceTcbInfo block of a given TCI node, -// - the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. -// - the "fwid" field must contain cumulative TCI measurement. -func testDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { - handle := getInitialContextHandle(d, c, t, simulation) - if simulation { - // Clean up contexts - defer func() { - err := c.DestroyContext(handle, DestroyDescendants) - if err != nil { - t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) - } - }() - } +// A tcg-dice-Ueid extension MUST be added +// This SHALL be populated by the LABEL input parameter to CertifyKey +// The extension SHOULD be marked as critical +func checkCertifyKeyTcgUeidExtension(t *testing.T, extensions []pkix.Extension, label []byte) { + t.Helper() - profile, err := GetTransportProfile(d) + ueid, err := getUeid(extensions) if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - var hashAlg asn1.ObjectIdentifier - if digestLen == 32 { - hashAlg = OidSHA256 - } else if digestLen == 48 { - hashAlg = OidSHA384 - } - - childTCI1 := make([]byte, digestLen) - for i := range childTCI1 { - childTCI1[i] = byte(i + 1) + t.Errorf("[ERROR]: tcg-dice-Ueid extension is missing: %v", err) } - // Set tciType to verify in UEID extension - tciType := uint32(2) - - // Derive Child context with input data, tag it and check TCI_CUMULATIVE - childCtx, err := c.DeriveChild(handle, - childTCI1, - DeriveChildFlags(InputAllowX509), - tciType, - 0) - - if err != nil { - t.Fatalf("[FATAL]: Error while creating child handle: %s", err) + if !reflect.DeepEqual(ueid.Ueid, label) { + // Ueid extn value doen not match the label + t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") } +} - handle = &childCtx.NewContextHandle +// Checks whether certificate extended key usage is as per spec +// OID for ExtendedKeyUsage Extension: 2.5.29.37 +// The ExtendedKeyUsage extension SHOULD be marked as critical +// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca +// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc +func checkCertifyKeyExtendedKeyUsages(t *testing.T, extensions []pkix.Extension, ca bool) { + t.Helper() - var childTcbInfo DiceTcbInfo - handle, childTcbInfo, err = getTcbInfoForHandle(c, handle) + extKeyUsage, err := getExtendedKeyUsages(extensions) if err != nil { - t.Fatalf("[FATAL]: Could not get TcbInfo: %v", err) - } - - // Check vendorInfo field in multitcb - if err = checkDiceTcbVendorInfo(childTcbInfo, d.GetLocality()); err != nil { - t.Errorf("[ERROR]: %v", err) + t.Errorf("[ERROR]: ExtKeyUsage extension is missing: %v", err) } - // Check tci type field in multitcb - if err = checkCurrentDiceTcbTciType(childTcbInfo, tciType); err != nil { - t.Errorf("[ERROR]: %v", err) + if len(extKeyUsage) == 0 { + t.Errorf("[ERROR]: The Extended Key Usage extension is empty") } - // Check hash algorithm field in multitcb - if err = checkDiceTcbHashAlgorithm(childTcbInfo, hashAlg); err != nil { - t.Errorf("[ERROR]: %v", err) + // Iterate over the OIDs in the ExtKeyUsage extension + isExtendedKeyUsageValid := false + var expectedKeyUsage asn1.ObjectIdentifier + expectedKeyUsageName := "" + if ca { + expectedKeyUsage = OidExtensionTcgDiceKpEca + expectedKeyUsageName = "tcg-dice-kp-eca" + } else { + expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc + expectedKeyUsageName = "tcg-dice-kp-attest-loc" } - // Extend TCI support is mandatory for this validation - if !d.GetSupport().ExtendTci { - t.Errorf("ExtendTCI is unsupported by profile, unable to run tests to verify TCI_CUMULATIVE measurement") - return + for _, oid := range extKeyUsage { + if oid.Equal(expectedKeyUsage) { + isExtendedKeyUsageValid = true + break + } } - - // Check dice tcb measurements of derived children - // Add one more child context - childTCI2 := make([]byte, digestLen) - for i := range childTCI2 { - childTCI2[i] = byte(i + 2) + if !isExtendedKeyUsageValid { + t.Errorf("[ERROR]: Certificate has IsCA: %v and does not contain specified key usage: %s", ca, expectedKeyUsageName) } +} - childCtx, err = c.DeriveChild(handle, - childTCI2, - DeriveChildFlags(InputAllowX509), - tciType, - 0) +// Checks for KeyUsage Extension as per spec +// If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign +// If IsCA = false, KeyUsage extension MUST contain only DigitalSignature +func checkCertifyKeyExtensions(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags, label []byte) { + t.Helper() + bc, err := getBasicConstraints(extensions) if err != nil { - t.Fatalf("[FATAL]: Error while creating child handle: %s", err) + t.Error(err) } - handle = &childCtx.NewContextHandle + checkCertifyKeyBasicConstraints(t, extensions, flags) + checkCertifyKeyExtendedKeyUsages(t, extensions, bc.IsCA) + checkCertifyKeyTcgUeidExtension(t, extensions, label) - // Get latest TCB information - certifiedKey, err := c.CertifyKey(handle, childTCI2, CertifyKeyX509, 0) + // Check MultiTcbInfo Extension structure + _, err = getMultiTcbInfo(extensions) if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %s", err) + t.Error(err) } - handle = &certifiedKey.Handle - leafCertBytes := certifiedKey.Certificate + //Check for keyusage extension + var allowedKeyUsages x509.KeyUsage - // Build list of tci_current for validation and use it for validating TCI measurements - currentTCIs := [][]byte{childTCI2, childTCI1} - if err = validateDiceTcbFwids(leafCertBytes, currentTCIs, digestLen); err != nil { - t.Errorf("[ERROR]: %v", err) + if bc.IsCA { + allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign + } else { + allowedKeyUsages = x509.KeyUsageDigitalSignature } -} -func checkPubKey(t *testing.T, p Profile, pubkey any, response CertifiedKey) { - var pubKeyInResponse ecdsa.PublicKey - switch p { - case ProfileP256SHA256: - pubKeyInResponse = ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: new(big.Int).SetBytes(response.Pub.X), - Y: new(big.Int).SetBytes(response.Pub.Y), - } - case ProfileP384SHA384: - pubKeyInResponse = ecdsa.PublicKey{ - Curve: elliptic.P384(), - X: new(big.Int).SetBytes(response.Pub.X), - Y: new(big.Int).SetBytes(response.Pub.Y), - } - default: - t.Errorf("[ERROR]: Unsupported profile %v", p) + usage, err := getKeyUsage(extensions) + if err != nil { + t.Error(err) } - ecdsaPub, ok := pubkey.(*ecdsa.PublicKey) - if !ok { - t.Fatal("[FATAL]: Public key is not a ecdsa key") + certKeyUsageList := getKeyUsageNames(usage) + allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) + if usage != allowedKeyUsages { + t.Errorf("[ERROR]: Certificate KeyUsage got %v but want %v ", certKeyUsageList, allowedKeyUsageList) } - if !(pubKeyInResponse.Equal(ecdsaPub)) { - t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the certificate.") - } } -// Checks whether the context handle is unchanged after certifyKey command when default context handle is used. -func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) { - if *handle != DefaultContextHandle { - t.Logf("[LOG]: Handle is not default context, skipping check...") - return +// Validates basic constraints in certificate returned by CertifyKey command +// against the flag set for input parameter. +// The BasicConstraints extension MUST be included +// If CertifyKey AddIsCA is set, IsCA MUST be set to true. +// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false +func checkCertifyKeyBasicConstraints(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags) { + t.Helper() + + flagsBuf := &bytes.Buffer{} + binary.Write(flagsBuf, binary.LittleEndian, flags) + + bc, err := getBasicConstraints(extensions) + if err != nil { + t.Error(err) } - if res.Handle != *handle { - t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle) + flagIsCA := CertifyAddIsCA&flags != 0 + if flagIsCA != bc.IsCA { + t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, bc.IsCA) } } // Parses X509 certificate func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { + t.Helper() failed := false var x509Cert *x509.Certificate @@ -357,13 +392,13 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate // Check whether certificate is DER encoded. if x509Cert, err = x509.ParseCertificate(certBytes); err != nil { - t.Fatalf("Could not parse certificate using crypto/x509: %v", err) + t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) } // Parse the cert with zcrypto so we can lint it. cert, err := zx509.ParseCertificate(certBytes) if err != nil { - t.Errorf("Could not parse certificate using zcrypto/x509: %v", err) + t.Errorf("[ERROR]: Could not parse certificate using zcrypto/x509: %v", err) failed = true } @@ -422,124 +457,197 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate return x509Cert } -// A tcg-dice-Ueid extension MUST be added -// This SHALL be populated by the LABEL input parameter to CertifyKey -// The extension SHOULD be marked as critical -func checkCertifyKeyTcgUeidExtension(t *testing.T, extensions []pkix.Extension, label []byte) { - t.Helper() +func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + if simulation { + c.DestroyContext(handle, DestroyDescendants) + } + }() - ueid, err := getUeid(extensions) + profile, err := GetTransportProfile(d) if err != nil { - t.Errorf("[ERROR]: tcg-dice-Ueid extension is missing: %v", err) + t.Fatalf("Could not get profile: %v", err) } + digestLen := profile.GetDigestSize() - if !reflect.DeepEqual(ueid.Ueid, label) { - // Ueid extn value doen not match the label - t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") + seqLabel := make([]byte, digestLen) + for i := range seqLabel { + seqLabel[i] = byte(i) } + + certifyKeyParams := []CertifyKeyParams{ + {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, + {Label: seqLabel, Flags: CertifyKeyFlags(0)}, + } + + for _, params := range certifyKeyParams { + // Get DPE leaf certificate from CertifyKey + certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) + if err != nil { + t.Fatalf("[FATAL]: Could not certify key: %v", err) + } + + // Get root and intermediate certificates to validate certificate chain of leaf cert + certChainBytes, err := c.GetCertificateChain() + if err != nil { + t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) + } + + leafCertBytes := certifyKeyResp.Certificate + + // Run X.509 linter on full certificate chain and file issues for errors + leafCert := checkCertificateStructure(t, leafCertBytes) + certChain := checkCertificateChain(t, certChainBytes) + + // Check default context handle is unchanged + checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) + + // Check public key and algorithm parameters are correct + checkPubKey(t, profile, leafCert.PublicKey, *certifyKeyResp) + + // Check all extensions + checkCertifyKeyExtensions(t, leafCert.Extensions, params.Flags, params.Label) + + // Ensure full certificate chain has valid signatures + // This also checks certificate lifetime, signatures as part of cert chain validation + validateLeafCertChain(t, certChain, leafCert) + + // Reassign handle for simulation mode. + // However, this does not impact in default mode because + // same default context handle is returned in default mode. + handle = &certifyKeyResp.Handle + } + // TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again. } -// Checks whether certificate extended key usage is as per spec -// OID for ExtendedKeyUsage Extension: 2.5.29.37 -// The ExtendedKeyUsage extension SHOULD be marked as critical -// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca -// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc -func checkCertifyKeyExtendedKeyUsages(t *testing.T, extensions []pkix.Extension, ca bool) { +// Builds and verifies certificate chain. +func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { t.Helper() + certsToProcess := []*x509.Certificate{leafCert} - extKeyUsage, err := getExtendedKeyUsages(extensions) + // Remove unhandled critical extensions and EKUs by x509 but defined in spec + removeTcgDiceCriticalExtensions(t, certsToProcess) + removeTcgDiceExtendedKeyUsages(t, certsToProcess) + + // Certificate chain validation for leaf + opts := buildVerifyOptions(t, certChain) + chains, err := leafCert.Verify(opts) if err != nil { - t.Errorf("[ERROR]: ExtKeyUsage extension is missing: %v", err) + t.Errorf("[ERROR]: Error verifying DPE leaf: %s", err.Error()) } - if len(extKeyUsage) == 0 { - t.Errorf("[ERROR]: The Extended Key Usage extension is empty") + // Log certificate chains linked to leaf + if len(chains) != 1 { + t.Errorf("[ERROR]: Unexpected number of cert chains: %d", len(chains)) } +} - // Iterate over the OIDs in the ExtKeyUsage extension - isExtendedKeyUsageValid := false - var expectedKeyUsage asn1.ObjectIdentifier - expectedKeyUsageName := "" - if ca { - expectedKeyUsage = OidExtensionTcgDiceKpEca - expectedKeyUsageName = "tcg-dice-kp-eca" - } else { - expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc - expectedKeyUsageName = "tcg-dice-kp-attest-loc" - } +// Builds Certificate chain verifier parameters. +func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions { + roots := x509.NewCertPool() + intermediates := x509.NewCertPool() - for _, oid := range extKeyUsage { - if oid.Equal(expectedKeyUsage) { - isExtendedKeyUsageValid = true - break + // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. + roots.AddCert(certChain[0]) + + for _, cert := range certChain[1:] { + if cert.Subject.String() == cert.Issuer.String() { + t.Errorf("[ERROR]: Found a self-signed certificate in middle of certificate chain returned by GetCertificateChain.") + continue } + intermediates.AddCert(cert) } - if !isExtendedKeyUsageValid { - t.Errorf("[ERROR]: Certificate has IsCA: %v and does not contain specified key usage: %s", ca, expectedKeyUsageName) + opts := x509.VerifyOptions{ + Roots: roots, + Intermediates: intermediates, + CurrentTime: time.Now().UTC(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, } + + return opts } -// // Checks for KeyUsage Extension as per spec -// // If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign -// // If IsCA = false, KeyUsage extension MUST contain only DigitalSignature -func checkCertifyKeyExtensions(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags, label []byte) { - t.Helper() +// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. +func getKeyUsageNames(keyUsage x509.KeyUsage) []string { + keyUsageNames := []string{} - bc, err := getBasicConstraints(extensions) - if err != nil { - t.Error(err) + if keyUsage&x509.KeyUsageDigitalSignature != 0 { + keyUsageNames = append(keyUsageNames, "DigitalSignature") } - checkCertifyKeyBasicConstraints(t, extensions, flags) - checkCertifyKeyExtendedKeyUsages(t, extensions, bc.IsCA) - checkCertifyKeyTcgUeidExtension(t, extensions, label) + if keyUsage&x509.KeyUsageContentCommitment != 0 { + keyUsageNames = append(keyUsageNames, "ContentCommitment") + } - // Check MultiTcbInfo Extension structure - _, err = getMultiTcbInfo(extensions) - if err != nil { - t.Error(err) + if keyUsage&x509.KeyUsageKeyEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "KeyEncipherment") } - //Check for keyusage extension - var allowedKeyUsages x509.KeyUsage + if keyUsage&x509.KeyUsageDataEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "DataEncipherment") + } - if bc.IsCA { - allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign - } else { - allowedKeyUsages = x509.KeyUsageDigitalSignature + if keyUsage&x509.KeyUsageKeyAgreement != 0 { + keyUsageNames = append(keyUsageNames, "KeyAgreement") } - usage, err := getKeyUsage(extensions) - if err != nil { - t.Error(err) + if keyUsage&x509.KeyUsageCertSign != 0 { + keyUsageNames = append(keyUsageNames, "CertSign") } - certKeyUsageList := getKeyUsageNames(usage) - allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) - if usage != allowedKeyUsages { - t.Errorf("[ERROR]: Certificate KeyUsage got %v but want %v ", certKeyUsageList, allowedKeyUsageList) + if keyUsage&x509.KeyUsageCRLSign != 0 { + keyUsageNames = append(keyUsageNames, "CRLSign") } + if keyUsage&x509.KeyUsageEncipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "EncipherOnly") + } + + if keyUsage&x509.KeyUsageDecipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "DecipherOnly") + } + + return keyUsageNames } -// Validates basic constraints in certificate returned by CertifyKey command -// against the flag set for input parameter. -// The BasicConstraints extension MUST be included -// If CertifyKey AddIsCA is set, IsCA MUST be set to true. -// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false -func checkCertifyKeyBasicConstraints(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags) { - t.Helper() +func checkPubKey(t *testing.T, p Profile, pubkey any, response CertifiedKey) { + var pubKeyInResponse ecdsa.PublicKey + switch p { + case ProfileP256SHA256: + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + case ProfileP384SHA384: + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P384(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + default: + t.Errorf("[ERROR]: Unsupported profile %v", p) + } - flagsBuf := &bytes.Buffer{} - binary.Write(flagsBuf, binary.LittleEndian, flags) + ecdsaPub, ok := pubkey.(*ecdsa.PublicKey) + if !ok { + t.Fatal("[FATAL]: Public key is not a ecdsa key") + } - bc, err := getBasicConstraints(extensions) - if err != nil { - t.Error(err) + if !(pubKeyInResponse.Equal(ecdsaPub)) { + t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the certificate.") } +} - flagIsCA := CertifyAddIsCA&flags != 0 - if flagIsCA != bc.IsCA { - t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, bc.IsCA) +// Checks whether the context handle is unchanged after certifyKey command when default context handle is used. +func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) { + if *handle != DefaultContextHandle { + t.Logf("[LOG]: Handle is not default context, skipping check...") + return + } + + if res.Handle != *handle { + t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle) } } diff --git a/verification/certs.go b/verification/certs.go index d26d34f6..8a7d3845 100644 --- a/verification/certs.go +++ b/verification/certs.go @@ -3,17 +3,13 @@ package verification import ( - "bytes" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" - "encoding/binary" "fmt" - "time" - - "golang.org/x/exp/slices" ) +// This file is used to test the certify key command. var ( OidExtensionKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 15} OidExtensionAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35} @@ -32,87 +28,8 @@ var ( OidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} ) -var TcgDiceCriticalExtensions = [...]string{ - OidExtensionTcgDiceMultiTcbInfo.String(), - OidExtensionTcgDiceUeid.String(), -} - -var TcgDiceExtendedKeyUsages = [...]string{ - OidExtensionTcgDiceKpIdentityLoc.String(), - OidExtensionTcgDiceKpAttestLoc.String(), -} - -// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} -// -// TcgUeid ::== SEQUENCE { -// ueid OCTET STRING -// } -type TcgUeidExtension struct { - Ueid []uint8 `asn1:"ueid,implicit"` -} - -// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} -// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo -// -// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} -// -// DiceTcbInfo ::== SEQUENCE { -// vendor [0] IMPLICIT UTF8String OPTIONAL, -// model [1] IMPLICIT UTF8String OPTIONAL, -// version [2] IMPLICIT UTF8String OPTIONAL, -// svn [3] IMPLICIT INTEGER OPTIONAL, -// layer [4] IMPLICIT INTEGER OPTIONAL, -// index [5] IMPLICIT INTEGER OPTIONAL, -// fwids [6] IMPLICIT FWIDLIST OPTIONAL, -// flags [7] IMPLICIT OperationalFlags OPTIONAL, -// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, -// type [9] IMPLICIT OCTET STRING OPTIONAL, -// } -// -// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID -// FWID ::== SEQUENCE { -// hashAlg OBJECT IDENTIFIER, -// digest OCTET STRING -// } -// -// OperationalFlags ::= BIT STRING { -// notConfigured (0), -// notSecure (1), -// recovery (2), -// debug (3) -// } - -type Fwid struct { - HashAlg asn1.ObjectIdentifier - Digest []byte -} - -type DiceTcbInfo struct { - Vendor string `asn1:"optional,tag:0,utf8"` - Model string `asn1:"optional,tag:1,utf8"` - Version string `asn1:"optional,tag:2,utf8"` - SVN int `asn1:"optional,tag:3"` - Layer int `asn1:"optional,tag:4"` - Index int `asn1:"optional,tag:5"` - Fwids []Fwid `asn1:"optional,tag:6"` - Flags OperationalFlag `asn1:"optional,tag:7"` - VendorInfo []byte `asn1:"optional,tag:8"` - Type []byte `asn1:"optional,tag:9"` -} - -type OperationalFlag int - -const ( - NotConfigured OperationalFlag = iota - NotSecure - Debug - Recovery -) - -type TcgMultiTcbInfo = []DiceTcbInfo - type BasicConstraints struct { - IsCA bool `asn1:"boolean"` + IsCA bool `asn1` PathLenConstraint int `asn1:"optional"` } @@ -123,11 +40,11 @@ func getMultiTcbInfo(extensions []pkix.Extension) (TcgMultiTcbInfo, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionTcgDiceMultiTcbInfo) { if !ext.Critical { - return multiTcbInfo, fmt.Errorf("TCG DICE MultiTcbInfo extension is not marked as CRITICAL") + return multiTcbInfo, fmt.Errorf("[ERROR]: TCG DICE MultiTcbInfo extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &multiTcbInfo) if err != nil { - return multiTcbInfo, fmt.Errorf("Failed to unmarshal MultiTcbInfo field: %v", err) + return multiTcbInfo, fmt.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) } break } @@ -140,11 +57,11 @@ func getBasicConstraints(extensions []pkix.Extension) (BasicConstraints, error) for _, ext := range extensions { if ext.Id.Equal(OidExtensionBasicConstraints) { if !ext.Critical { - return bc, fmt.Errorf("BasicConstraints extension is not marked as CRITICAL") + return bc, fmt.Errorf("[ERROR]: BasicConstraints extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &bc) if err != nil { - return bc, fmt.Errorf("Failed to unmarshal BasicConstraints extension: %v", err) + return bc, fmt.Errorf("[ERROR]: Failed to unmarshal BasicConstraints extension: %v", err) } break } @@ -157,11 +74,11 @@ func getUeid(extensions []pkix.Extension) (TcgUeidExtension, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionTcgDiceUeid) { if !ext.Critical { - return ueid, fmt.Errorf("UEID extension is not marked as CRITICAL") + return ueid, fmt.Errorf("[ERROR]: UEID extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &ueid) if err != nil { - return ueid, fmt.Errorf("Failed to unmarshal UEID extension: %v", err) + return ueid, fmt.Errorf("[ERROR]: Failed to unmarshal UEID extension: %v", err) } break } @@ -174,11 +91,11 @@ func getExtendedKeyUsages(extensions []pkix.Extension) ([]asn1.ObjectIdentifier, for _, ext := range extensions { if ext.Id.Equal(OidExtensionExtKeyUsage) { if !ext.Critical { - return eku, fmt.Errorf("ExtKeyUsage extension is not marked as CRITICAL") + return eku, fmt.Errorf("[ERROR]: ExtKeyUsage extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &eku) if err != nil { - return eku, fmt.Errorf("Failed to unmarshal ExtKeyUsage extension: %v", err) + return eku, fmt.Errorf("[ERROR]: Failed to unmarshal ExtKeyUsage extension: %v", err) } break } @@ -191,11 +108,11 @@ func getKeyUsage(extensions []pkix.Extension) (x509.KeyUsage, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionKeyUsage) { if !ext.Critical { - return x509.KeyUsage(0), fmt.Errorf("KeyUsage extension is not marked as CRITICAL") + return x509.KeyUsage(0), fmt.Errorf("[ERROR]: KeyUsage extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &usageBits) if err != nil { - return x509.KeyUsage(0), fmt.Errorf("Failed to unmarshal KeyUsage extension: %v", err) + return x509.KeyUsage(0), fmt.Errorf("[ERROR]: Failed to unmarshal KeyUsage extension: %v", err) } break } @@ -249,274 +166,3 @@ func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (*ContextHandle, Di return outHandle, multiTcbInfo[0], nil } - -// Removes the critical extensions that are unknown to x509 package -// but defined in DPE certificate profile specification for cert chain validation -// UnhandledCriticalExtensions may have only custom extensions mentioned in spec -// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec -// positive case expects the unknownExtnMap to be empty. -func removeTcgDiceCriticalExtensions(certs []*x509.Certificate) error { - unknownExtnMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnhandledCriticalExtensions) > 0 { - unknownExtns := []string{} - for _, extn := range cert.UnhandledCriticalExtensions { - if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { - unknownExtns = append(unknownExtns, extn.String()) - } - } - - if len(unknownExtnMap) == 0 { - cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} - } else { - unknownExtnMap[cert.Subject.String()] = unknownExtns - } - } - } - // The error details in this map will be logged - msg := "" - if len(unknownExtnMap) > 0 { - for certSubject, ext := range unknownExtnMap { - msg += fmt.Errorf("Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() - } - return fmt.Errorf("%s", msg) - } - return nil -} - -// Ignores extended key usages that are unknown to x509 package -// but atleast defined in DPE certificate profile specification for cert chain validation -// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec -// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec -// positive case expects the unknownKeyUsagesMap to be empty. -func removeTcgDiceExtendedKeyUsages(certs []*x509.Certificate) error { - unknownKeyUsagesMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnknownExtKeyUsage) > 0 { - unknownKeyUsages := []string{} - for _, eku := range cert.UnknownExtKeyUsage { - if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { - unknownKeyUsages = append(unknownKeyUsages, eku.String()) - } - } - - if len(unknownKeyUsagesMap) == 0 { - cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} - } else { - unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages - } - } - } - // The error details in this map will be logged - msg := "" - if len(unknownKeyUsagesMap) > 0 { - for certSubject, ext := range unknownKeyUsagesMap { - msg += fmt.Errorf("Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() - } - return fmt.Errorf("%s", msg) - } - return nil -} - -// Checks whether the VendorInfo is 4-bytes TARGET_LOCALITY parameter -func checkDiceTcbVendorInfo(currentTcbInfo DiceTcbInfo, targetLocality uint32) error { - var err error - expectedVendorInfo := make([]byte, 4) - binary.BigEndian.PutUint32(expectedVendorInfo, targetLocality) - if !bytes.Equal(currentTcbInfo.VendorInfo, expectedVendorInfo) { - err = fmt.Errorf("Unexpected VendorInfo for current DICE TCB block, want %v but got %v", expectedVendorInfo, currentTcbInfo.VendorInfo) - } - return err -} - -// Checks whether INPUT_TYPE passed to a deriveChild Request -// populates the "type" field in the DiceTcbInfo extension. -func checkCurrentDiceTcbTciType(currentTcbInfo DiceTcbInfo, expectedTciType uint32) error { - var err error - expectedTciTypeBytes := make([]byte, 4) - binary.BigEndian.PutUint32(expectedTciTypeBytes, expectedTciType) - if !bytes.Equal(currentTcbInfo.Type, expectedTciTypeBytes) { - err = fmt.Errorf("Unexpected TCI type for current DICE TCB block, want %v but got %v", expectedTciTypeBytes, currentTcbInfo.Type) - } - return err -} - -// Checks whether the Hash Algorithm field in FWID block is correct -func checkDiceTcbHashAlgorithm(currentTcbInfo DiceTcbInfo, hashAlg asn1.ObjectIdentifier) error { - for _, fwid := range currentTcbInfo.Fwids { - if !fwid.HashAlg.Equal(hashAlg) { - return fmt.Errorf("Unexpected hash algorithm in FWID block, expected %s but got %s", hashAlg, fwid.HashAlg) - } - } - return nil -} - -// Builds and verifies certificate chain. -func validateLeafCertChain(certChain []*x509.Certificate, leafCert *x509.Certificate) error { - var err error - certsToProcess := []*x509.Certificate{leafCert} - - // Remove unhandled critical extensions reported by x509 but defined in spec - if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { - return err - } - - // Remove unhandled extended key usages reported by x509 but defined in spec - if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { - return err - } - - // Build verify options - var opts *x509.VerifyOptions - if opts, err = buildVerifyOptions(certChain); err != nil { - return err - } - - // Certificate chain validation for leaf - chains, err := leafCert.Verify(*opts) - if err != nil { - // Unable to build certificate chain from leaf to root - return fmt.Errorf("Error verifying DPE leaf: %s", err.Error()) - } - - // Log certificate chains linked to leaf - if len(chains) != 1 { - return fmt.Errorf("Unexpected number of cert chains: %d", len(chains)) - } - return nil -} - -// Builds Certificate chain verifier parameters. -func buildVerifyOptions(certChain []*x509.Certificate) (*x509.VerifyOptions, error) { - var err error - roots := x509.NewCertPool() - intermediates := x509.NewCertPool() - - // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. - roots.AddCert(certChain[0]) - - for _, cert := range certChain[1:] { - if cert.Subject.String() == cert.Issuer.String() { - return nil, fmt.Errorf("Found a self-signed certificate in middle of certificate chain returned by GetCertificateChain") - } - intermediates.AddCert(cert) - } - opts := x509.VerifyOptions{ - Roots: roots, - Intermediates: intermediates, - CurrentTime: time.Now().UTC(), - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, - } - - return &opts, err -} - -// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. -func getKeyUsageNames(keyUsage x509.KeyUsage) []string { - keyUsageNames := []string{} - - if keyUsage&x509.KeyUsageDigitalSignature != 0 { - keyUsageNames = append(keyUsageNames, "DigitalSignature") - } - - if keyUsage&x509.KeyUsageContentCommitment != 0 { - keyUsageNames = append(keyUsageNames, "ContentCommitment") - } - - if keyUsage&x509.KeyUsageKeyEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "KeyEncipherment") - } - - if keyUsage&x509.KeyUsageDataEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "DataEncipherment") - } - - if keyUsage&x509.KeyUsageKeyAgreement != 0 { - keyUsageNames = append(keyUsageNames, "KeyAgreement") - } - - if keyUsage&x509.KeyUsageCertSign != 0 { - keyUsageNames = append(keyUsageNames, "CertSign") - } - - if keyUsage&x509.KeyUsageCRLSign != 0 { - keyUsageNames = append(keyUsageNames, "CRLSign") - } - - if keyUsage&x509.KeyUsageEncipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "EncipherOnly") - } - - if keyUsage&x509.KeyUsageDecipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "DecipherOnly") - } - - return keyUsageNames -} - -// Verifies the TCI_Current and TCI_Cumulative of dice tcb information blocks -func verifyDiceTcbDigest(tcbInfo DiceTcbInfo, wantCurrentTCI []byte, lastCumulativeTCI []byte) error { - var err error - - // Check TCI_CURRENT - currentTCI := tcbInfo.Fwids[0].Digest - if !bytes.Equal(currentTCI, wantCurrentTCI) { - err = fmt.Errorf("Unexpected TCI_CURRENT digest, want %v but got %v", wantCurrentTCI, currentTCI) - } - - // Check TCI_CUMULATIVE against expected cumulative TCI - wantCumulativeTCI := computeExpectedCumulative(lastCumulativeTCI, currentTCI) - cumulativeTCI := tcbInfo.Fwids[1].Digest - if !bytes.Equal(cumulativeTCI, wantCumulativeTCI) { - err = fmt.Errorf("Unexpected TCI_CUMULATIVE value, want %v but got %v", wantCumulativeTCI, cumulativeTCI) - } - return err -} - -// Checks the FWID block's Digest. -// FWID at index 0 has the TCI_CURRENT as digest -// FWID at index 1 has the TCI_CUMULATIVE as digest -// FWID array always has two digest/hashAlg blocks when "ExtendTci" is supported by DPE profile. -func validateDiceTcbFwids(leafCertBytes []byte, currentTcis [][]byte, digestLen int) error { - var leafCert *x509.Certificate - var err error - - // Check whether certificate is DER encoded. - if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { - return err - } - - // Get DICE information from MultiTcbInfo Extension - var multiTcbInfo []DiceTcbInfo - if multiTcbInfo, err = getMultiTcbInfo(leafCert.Extensions); err != nil { - return err - } - - if len(multiTcbInfo) == 0 { - return fmt.Errorf("Certificate MutliTcbInfo is empty") - } - - // Calculate expected cumulative value - defaultTci := make([]byte, digestLen) - - // Check cumulative, current TCI at the last index of multitcb info - // It must have default TCI value - lastIndex := len(multiTcbInfo) - 1 - if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[0].Digest, defaultTci) { - return fmt.Errorf("Current TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[0].Digest) - } - - if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[1].Digest, defaultTci) { - return fmt.Errorf("Cumulative TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[1].Digest) - } - - // Check cumulative, current TCI of other indices if any - lastCumulativeTCI := defaultTci - multiTcbInfo = multiTcbInfo[:lastIndex] - - for i, tcbinfo := range multiTcbInfo { - wantCurrentTci := currentTcis[i] - verifyDiceTcbDigest(tcbinfo, wantCurrentTci, lastCumulativeTCI) - } - return err -} diff --git a/verification/extendTCI.go b/verification/extendTCI.go index aa3a5c9f..e46d1cdb 100644 --- a/verification/extendTCI.go +++ b/verification/extendTCI.go @@ -35,7 +35,7 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { if err != nil { t.Fatal(err) } - lastCumulativeTCI := tcbInfo.Fwids[1].Digest + lastCumulative := tcbInfo.Fwids[1].Digest // Set current TCI value _, err = c.ExtendTCI(handle, tciValue) @@ -43,17 +43,9 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { t.Fatalf("[FATAL]: Could not extend TCI: %v", err) } - // Refresh TCB info - _, tcbInfo, err = getTcbInfoForHandle(c, handle) - if err != nil { - t.Fatal(err) - } - - // Check current and cumulative measurement in DiceTcb info block - wantCurrentTCI := tciValue - if err = verifyDiceTcbDigest(tcbInfo, wantCurrentTCI, lastCumulativeTCI); err != nil { - t.Errorf("[ERROR]: %v", err) - } + // Check current and cumulative measurement by CertifyKey + expectedCumulative := computeExpectedCumulative(lastCumulative, tciValue) + verifyMeasurements(c, t, handle, tciValue, expectedCumulative) } func computeExpectedCumulative(lastCumulative []byte, tciValue []byte) []byte { @@ -161,3 +153,21 @@ func TestExtendTciOnDerivedContexts(d TestDPEInstance, c DPEClient, t *testing.T t.Errorf("[ERROR]: Child node's cumulative TCI %x, expected %x", childTcbInfo.Fwids[1].Digest, wantCumulativeTCI) } } + +func verifyMeasurements(c DPEClient, t *testing.T, handle *ContextHandle, expectedCurrent []byte, expectedCumulative []byte) { + handle, tcbInfo, err := getTcbInfoForHandle(c, handle) + if err != nil { + t.Fatal(err) + } + + // Check that the last TcbInfo current/cumulative are as expected + current := tcbInfo.Fwids[0].Digest + cumulative := tcbInfo.Fwids[1].Digest + if !bytes.Equal(current, expectedCurrent) { + t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrent, current) + } + + if !bytes.Equal(cumulative, expectedCumulative) { + t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulative, cumulative) + } +} diff --git a/verification/getCertificateChain.go b/verification/getCertificateChain.go index 66f8662e..362ed85c 100644 --- a/verification/getCertificateChain.go +++ b/verification/getCertificateChain.go @@ -102,29 +102,21 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { // Build certificate chain and calls to validateSignature on each chain. func validateCertChain(t *testing.T, certChain []*x509.Certificate) { t.Helper() - var err error certsToProcess := certChain // Remove unhandled critical extensions reported by x509 but defined in spec - if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { - t.Errorf("[ERROR]: %v", err) - } + removeTcgDiceCriticalExtensions(t, certsToProcess) // Remove unhandled extended key usages reported by x509 but defined in spec - if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { - t.Errorf("[ERROR]: %v", err) - } + removeTcgDiceExtendedKeyUsages(t, certsToProcess) // Build verify options - opts, err := buildVerifyOptions(certChain) - if err != nil { - t.Errorf("[ERROR]: %v", err) - } + opts := buildVerifyOptions(t, certChain) // Certificate chain validation for each intermediate certificate for _, cert := range certChain { - chains, err := cert.Verify(*opts) + chains, err := cert.Verify(opts) if err != nil { t.Errorf("[ERROR]: Error in Certificate Chain of %s: %s", cert.Subject, err.Error()) } diff --git a/verification/simulator.go b/verification/simulator.go index d919bbc8..a95314e1 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -234,11 +234,6 @@ func GetSimulatorTargets() []TestTarget { getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), AllTestCases, }, - { - "CertifyKey_TcbValidation", - getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci"}), - []TestCase{DiceTcbValidationTestCase, DiceTcbValidationSimulationTestCase}, - }, { "DeriveChild", getTestTarget([]string{"AutoInit", "X509", "IsCA"}), diff --git a/verification/verification.go b/verification/verification.go index f00d0eb4..cda4efca 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -27,19 +27,13 @@ var InitializeContextSimulationTestCase = TestCase{ "InitializeContextSimulation", TestInitializeSimulation, []string{"Simulation"}, } var CertifyKeyTestCase = TestCase{ - "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA", "RotateContext"}, -} -var CertifyKeySimulationTestCase = TestCase{ - "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext"}, + "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA"}, } var CertifyKeyCsrTestCase = TestCase{ "CertifyKeyCsr", TestCertifyKey_Csr, []string{"AutoInit", "Csr", "IsCA"}, } -var DiceTcbValidationTestCase = TestCase{ - "CheckDiceTcbInfo", TestDiceTcbInfo, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, -} -var DiceTcbValidationSimulationTestCase = TestCase{ - "CheckDiceTcbInfoInSimulationMode", TestDiceTcbInfoSimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, +var CertifyKeySimulationTestCase = TestCase{ + "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA"}, } var GetCertificateChainTestCase = TestCase{ "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, From 28f22bd7f1215c4d51a8a95de70d7d4d15c5f8f9 Mon Sep 17 00:00:00 2001 From: hpya93 Date: Wed, 20 Dec 2023 00:17:13 +0530 Subject: [PATCH 17/17] review comments --- verification/deriveChild.go | 4 ++-- verification/verification.go | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/verification/deriveChild.go b/verification/deriveChild.go index d920288d..adc2307f 100644 --- a/verification/deriveChild.go +++ b/verification/deriveChild.go @@ -77,7 +77,7 @@ func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { // Validates DerivedChild command with ChangeLocality flag. func TestChangeLocality(d TestDPEInstance, c DPEClient, t *testing.T) { if !d.HasLocalityControl() { - t.Skip("WARNING: DPE profile does not have control over locality. Skipping this test...") + t.Skip("WARNING: DPE target does not have control over locality. Skipping this test...") } var resp *DeriveChildResp @@ -237,7 +237,7 @@ func TestMaxTCIs(d TestDPEInstance, c DPEClient, t *testing.T) { func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { if !d.HasLocalityControl() { - t.Skip("WARNING: DPE profile does not have control over locality, DeriveContext in Simulation mode cannot be tested without this support. Skipping this test...") + t.Skip("WARNING: DPE target does not have control over locality, DeriveContext in Simulation mode cannot be tested without this support. Skipping this test...") } var resp *DeriveChildResp diff --git a/verification/verification.go b/verification/verification.go index d898c7f4..13be30a0 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -159,6 +159,11 @@ var AllTestCases = []TestCase{ WrongLocalityTestCase, } +var IrreversibleTestCases = []TestCase{ + DeriveChildTestCase, + DeriveChildSimulationTestCase, +} + // RunTargetTestCases runs all test cases for target func RunTargetTestCases(target TestTarget, t *testing.T) { // This needs to be in a separate function to make sure it is powered off before running the