From b123db5abe4473c05b6d920953cc56a87bf4966c Mon Sep 17 00:00:00 2001 From: Jay Hou Date: Mon, 12 Feb 2024 14:54:06 +0000 Subject: [PATCH] Allow passing the witness identity counter to the Trusted Applet. (#142) * Remove storage from RPMB struct. * Add fake RPMB. * Make counter read optional for RPMB. * Use 2D memory array for fake RPMB. * Add sector constants and read/write for MMC blocks related to new witness identity. * Call increment when new witness identity for both MMC and RPMB cases. * Add RPCs for reading the witness identity counter. * Use fake RPMB to implement the counter. * Add identity counter to witness status data structures. * Move identity counter out of WitnessStatus. * Set identity counter in status. * Fix getStatus. * Don't need to pass in RPMB to ctl. * Fix compilation errors. * Add env vars for toggling fake storage to Dockerfile. * Add back / fix fake rpmb init() --- Dockerfile | 4 ++++ trusted_os/ctl.go | 18 ++++++++++++++--- trusted_os/flash.go | 20 ++++++++++-------- trusted_os/rpc.go | 17 +++++++++++++++- trusted_os/rpmb.go | 43 +++++++++++++++++++++++++++++++++++++++ trusted_os/rpmb_fake.go | 45 ++++++++++++++++++++++++++++++++++++----- 6 files changed, 130 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 93190d4..56ed6da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,8 @@ ARG OS_PUBLIC_KEY2 ARG GIT_SEMVER_TAG ARG BEE ARG DEBUG +ARG FAKE_RPMB=1 +ARG FAKE_STORAGE=0 # Install dependencies. RUN apt-get update && apt-get install -y make wget u-boot-tools binutils-arm-none-eabi @@ -35,6 +37,8 @@ ENV LOG_ORIGIN=${LOG_ORIGIN} \ OS_PUBLIC_KEY1="/tmp/os1.pub" \ OS_PUBLIC_KEY2="/tmp/os2.pub" \ GIT_SEMVER_TAG=${GIT_SEMVER_TAG} \ + FAKE_RPMB=${FAKE_RPMB} \ + FAKE_STORAGE=${FAKE_STORAGE} \ BEE=${BEE} \ DEBUG=${DEBUG} diff --git a/trusted_os/ctl.go b/trusted_os/ctl.go index 8ff11a5..25c39af 100644 --- a/trusted_os/ctl.go +++ b/trusted_os/ctl.go @@ -51,7 +51,7 @@ type controlInterface struct { ota *otaBuffer } -func getStatus() (s *api.Status) { +func (ctl *controlInterface) getStatus() (s *api.Status) { version, _ := parseVersion(Version) s = &api.Status{ @@ -61,8 +61,20 @@ func getStatus() (s *api.Status) { Build: Build, Version: version, Runtime: fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH), - // TODO(jayhou): set IdentityCounter here. } + + rpmb := ctl.RPC.RPMB + if rpmb == nil { + log.Printf("cannot get witness identity counter because RPMB is nil") + } else { + count, err := rpmb.witnessIdentityCounter() + if err != nil { + log.Printf("cannot get witness identity counter: %v", err) + } else { + s.IdentityCounter = count + } + } + if witnessStatus != nil { s.Witness = &api.WitnessStatus{ Identity: witnessStatus.Identity, @@ -87,7 +99,7 @@ func (ctl *controlInterface) HandleMessage(_ []byte) (_ []byte) { } func (ctl *controlInterface) Status(_ []byte) (res []byte) { - res, _ = proto.Marshal(getStatus()) + res, _ = proto.Marshal(ctl.getStatus()) return } diff --git a/trusted_os/flash.go b/trusted_os/flash.go index 738a60d..d303930 100644 --- a/trusted_os/flash.go +++ b/trusted_os/flash.go @@ -34,14 +34,18 @@ import ( const ( expectedBlockSize = 512 // Expected size of MMC block in bytes - otaLimit = 31457280 - taConfBlock = 0x200000 - taBlockA = 0x200050 - taBlockB = 0x2FD050 - osConfBlock = 0x5000 - osBlockA = 0x5050 - osBlockB = 0x102828 - batchSize = 2048 + + otaLimit = 31457280 + + taConfBlock = 0x200000 + taBlockA = 0x200050 + taBlockB = 0x2FD050 + + osConfBlock = 0x5000 + osBlockA = 0x5050 + osBlockB = 0x102828 + + batchSize = 2048 ) const ( diff --git a/trusted_os/rpc.go b/trusted_os/rpc.go index da87577..62bad47 100644 --- a/trusted_os/rpc.go +++ b/trusted_os/rpc.go @@ -17,6 +17,7 @@ package main import ( "crypto/aes" "crypto/sha256" + "encoding/binary" "errors" "log" "net" @@ -40,6 +41,7 @@ type RPC struct { Storage Card Ctx *monitor.ExecCtx Cfg []byte + Ctl controlInterface Diversifier [32]byte } @@ -104,7 +106,7 @@ func (r *RPC) Status(_ any, status *api.Status) error { return errors.New("invalid argument") } - s := getStatus() + s := r.Ctl.getStatus() *status = *s return nil @@ -171,6 +173,19 @@ func (r *RPC) ReadRPMB(buf []byte, n *uint32) error { return r.RPMB.transfer(taUserSector, buf, n, false) } +// ReadIdentityCounterRPMB performs an authenticated data transfer from the card RPMB +// partition sector allocated to the witness identity counter. It returns the +// value stored in this area. +func (r *RPC) ReadIdentityCounterRPMB(_ any, counter *uint32) error { + buf := make([]byte, witnessIdentityCounterLength) + if err := r.RPMB.transfer(witnessIdentityCounterSector, buf, nil, false); err != nil { + return err + } + + *counter = binary.BigEndian.Uint32(buf) + return nil +} + // DeriveKey derives a hardware unique key in a manner equivalent to PKCS#11 // C_DeriveKey with CKM_AES_CBC_ENCRYPT_DATA. // diff --git a/trusted_os/rpmb.go b/trusted_os/rpmb.go index ea6dc58..635225f 100644 --- a/trusted_os/rpmb.go +++ b/trusted_os/rpmb.go @@ -40,12 +40,14 @@ import ( const ( // RPMB sector for CVE-2020-13799 mitigation dummySector = 0 + // version epoch length versionLength = 4 // RPMB sector for OS rollback protection osVersionSector = 1 // RPMB sector for TA rollback protection taVersionSector = 2 + // RPMB sector for TA use taUserSector = 3 // RPMB OTP flag bank @@ -53,6 +55,11 @@ const ( // RPMB OTP flag word rpmbFuseWord = 6 + // witness identity counter length - uint32 + witnessIdentityCounterLength = 4 + // RPMB sector for witness identity counter + witnessIdentityCounterSector = 7 + diversifierMAC = "ArmoryWitnessMAC" iter = 4096 ) @@ -216,3 +223,39 @@ func (r *RPMB) transfer(offset uint16, buf []byte, n *uint32, write bool) (err e return } + +// witnessIdentityCounter gets the witness identity counter from the RPMB area. +func (r *RPMB) witnessIdentityCounter() (counter uint32, err error) { + if r.partition == nil { + return 0, errors.New("RPMB has not been initialized") + } + + rBuf := make([]byte, witnessIdentityCounterLength) + if err = r.partition.Read(witnessIdentityCounterSector, rBuf); err != nil { + return 0, err + } + return binary.BigEndian.Uint32(rBuf), nil +} + +// incrementWitnessIdentityCounter increments the counter in the RPMB area to +// differentiate a new witness identity. +func (r *RPMB) incrementWitnessIdentityCounter() (err error) { + if r.partition == nil { + return errors.New("RPMB has not been initialized") + } + + // Read + rBuf := make([]byte, witnessIdentityCounterLength) + if err = r.partition.Read(witnessIdentityCounterSector, rBuf); err != nil { + return err + } + counter := binary.BigEndian.Uint32(rBuf) + + // Increment + counter++ + + // Write + wBuf := make([]byte, witnessIdentityCounterLength) + binary.BigEndian.PutUint32(wBuf, counter) + return r.partition.Write(witnessIdentityCounterSector, wBuf) +} diff --git a/trusted_os/rpmb_fake.go b/trusted_os/rpmb_fake.go index e9d3e97..25099d0 100644 --- a/trusted_os/rpmb_fake.go +++ b/trusted_os/rpmb_fake.go @@ -36,22 +36,29 @@ const ( // RPMB sector for TA use taUserSector = 3 + // witness identity counter length - uint32 + witnessIdentityCounterLength = 4 + // RPMB sector for witness identity counter + witnessIdentityCounterSector = 4 + sectorLength = 256 numSectors = 16 ) type RPMB struct { - mem [numSectors][sectorLength]byte + mem [numSectors][]byte counter uint32 } func newRPMB(_ Card) (*RPMB, error) { - return &RPMB{ - mem: make(map[numSectors][sectorLength]byte), - }, nil + r := &RPMB{} + for i := 0; i < numSectors; i++ { + r.mem[i] = make([]byte, sectorLength) + } + return r, nil } -func r (*RPMB) init() error { +func (r *RPMB) init() error { return nil } @@ -135,3 +142,31 @@ func (r *RPMB) transfer(sector uint16, buf []byte, n *uint32, write bool) (err e } return } + +// witnessIdentityCounter gets the witness identity counter from the RPMB area. +func (r *RPMB) witnessIdentityCounter() (counter uint32, err error) { + rBuf := make([]byte, witnessIdentityCounterLength) + if err := r.transfer(witnessIdentityCounterSector, rBuf, nil, false); err != nil { + return 0, err + } + return binary.BigEndian.Uint32(rBuf), nil +} + +// incrementWitnessIdentityCounter increments the counter in the RPMB area to +// differentiate a new witness identity. +func (r *RPMB) incrementWitnessIdentityCounter() error { + // Read + rBuf := make([]byte, witnessIdentityCounterLength) + if err := r.transfer(witnessIdentityCounterSector, rBuf, nil, false); err != nil { + return err + } + counter := binary.BigEndian.Uint32(rBuf) + + // Increment + counter++ + + // Write + wBuf := make([]byte, witnessIdentityCounterLength) + binary.BigEndian.PutUint32(wBuf, counter) + return r.transfer(witnessIdentityCounterSector, wBuf, nil, true) +}