diff --git a/go.mod b/go.mod index d14cd27..a54263f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/transparency-dev/armored-witness-os -go 1.24.1 +go 1.24.3 require ( github.com/coreos/go-semver v0.3.1 @@ -12,12 +12,13 @@ require ( github.com/transparency-dev/armored-witness-common v0.0.0-20240313170947-0b19d0fb8b95 github.com/transparency-dev/merkle v0.0.2 github.com/transparency-dev/serverless-log v0.0.0-20231215122707-66f68a7705f5 - github.com/usbarmory/GoTEE v0.0.0-20240913144333-7e62563c0628 + github.com/usbarmory/GoTEE v0.0.0-20250318141819-064601644998 github.com/usbarmory/armory-boot v0.0.0-20240924115649-09d0327c3c99 github.com/usbarmory/crucible v0.0.0-20240221192724-1595f2219655 github.com/usbarmory/imx-usbnet v0.0.0-20240304152630-ca189bf3b3c1 github.com/usbarmory/imx-usbserial v0.0.0-20230503192150-40b6298b31f8 - github.com/usbarmory/tamago v0.0.0-20250327164348-77f2a17385b6 + github.com/usbarmory/rpmb v0.0.0-20250528115648-e4c4b45ca899 + github.com/usbarmory/tamago v0.0.0-20250507084546-5652946876c4 golang.org/x/crypto v0.39.0 golang.org/x/mod v0.25.0 google.golang.org/protobuf v1.36.6 diff --git a/go.sum b/go.sum index 624f59e..ba871a9 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg= github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE= github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a h1:BH1SOPEvehD2kVrndDnGJiUF0TrBpNs+iyYocu6h0og= github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= -github.com/usbarmory/GoTEE v0.0.0-20240913144333-7e62563c0628 h1:PGlLJYe1YMmzmSYXhEkOSXSrQjV/mXk6CNk5LTgnndM= -github.com/usbarmory/GoTEE v0.0.0-20240913144333-7e62563c0628/go.mod h1:solbXmDpRv6u6CmfHiFi3rwsYoTlZXToith669WnvgM= +github.com/usbarmory/GoTEE v0.0.0-20250318141819-064601644998 h1:q9SRKEBHh511fqjCh61Rhbc/E4ooscNjvd+cjxrwwYw= +github.com/usbarmory/GoTEE v0.0.0-20250318141819-064601644998/go.mod h1:uEfj6hLaVWKoi1ZAUtiMsJKUBUj65E5U5K/QxZi2hz8= github.com/usbarmory/armory-boot v0.0.0-20240924115649-09d0327c3c99 h1:gDYQA/MDwqfTW5kRIqMcZ/rLlMwSyHJ9fIoWDIBCTLw= github.com/usbarmory/armory-boot v0.0.0-20240924115649-09d0327c3c99/go.mod h1:rhSWQ269NlXN2Nn3qZawWjqXBgbxtnx118RbJ2H6IlQ= github.com/usbarmory/crucible v0.0.0-20240221192724-1595f2219655 h1:n3JkWqsxKsbX2SKy+ac3v2rgEmTWfA/s0SC5kHlJGBY= @@ -65,9 +65,11 @@ github.com/usbarmory/imx-usbnet v0.0.0-20240304152630-ca189bf3b3c1 h1:Ba8KE+wt6b github.com/usbarmory/imx-usbnet v0.0.0-20240304152630-ca189bf3b3c1/go.mod h1:gJsQWSa5rjprEZb8/NqDzoOPxk6LTuEPsPiqpbrEUjw= github.com/usbarmory/imx-usbserial v0.0.0-20230503192150-40b6298b31f8 h1:VPruqXJEJxTweSRyx3NIkiIqQl9ppZHp4wZnL8+Y0aI= github.com/usbarmory/imx-usbserial v0.0.0-20230503192150-40b6298b31f8/go.mod h1:XfTrYj8Ik3ljit1cSHTcsXs7lyJ/QMsplPDX8+g5s7c= +github.com/usbarmory/rpmb v0.0.0-20250528115648-e4c4b45ca899 h1:cMmPYvUtVhg4FtplWHhhZN93SP0bXT3326SKXiA/ORQ= +github.com/usbarmory/rpmb v0.0.0-20250528115648-e4c4b45ca899/go.mod h1:k6asGjUwhbf8FbWKbwL3nmdcz6oxzPYx3XhoMF19Is8= github.com/usbarmory/tamago v0.0.0-20220823080407-04f05cf2a5a3/go.mod h1:Lok79mjbJnhoBGqhX5cCUsZtSemsQF5FNZW+2R1dRr8= -github.com/usbarmory/tamago v0.0.0-20250327164348-77f2a17385b6 h1:bUPSnUv06M5Ds+iq3MRD+pgQOjozfX3wzEzkzxpeUgo= -github.com/usbarmory/tamago v0.0.0-20250327164348-77f2a17385b6/go.mod h1:NL88q9ZsIPYFzXaosAeKgu1Kr5i1k4Rau3wnbNBL5bY= +github.com/usbarmory/tamago v0.0.0-20250507084546-5652946876c4 h1:v7E+9bzBJPfup/R5hmdw7jwTWzk58SlvI6u400UC9qg= +github.com/usbarmory/tamago v0.0.0-20250507084546-5652946876c4/go.mod h1:BtIwki3LlSlQJ/sW1wL2unqgYndZsSDioeyI3bVtZO8= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= diff --git a/rpmb/op.go b/rpmb/op.go deleted file mode 100644 index bbf4b10..0000000 --- a/rpmb/op.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2022 The Armored Witness OS authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package rpmb - -import ( - "bytes" - "crypto/hmac" - "crypto/rand" - "crypto/sha256" - "encoding/binary" - "errors" - "fmt" - "log" -) - -const ( - FrameLength = 512 - macOffset = 284 -) - -// p99, Table 18 — RPMB Request/Response Message Types, JESD84-B51 -const ( - AuthenticationKeyProgramming = iota + 1 - WriteCounterRead - AuthenticatedDataWrite - AuthenticatedDataRead - ResultRead - AuthenticatedDeviceConfigurationWrite - AuthenticatedDeviceConfigurationRead -) - -// p100, Table 20 — RPMB Operation Results, JESD84-B51 -const ( - OperationOK = iota - GeneralFailure - AuthenticationFailure - CounterFailure - AddressFailure - WriteFailure - ReadFailure - AuthenticationKeyNotYetProgrammed -) - -type OperationError struct { - Result uint16 -} - -func (e *OperationError) Error() string { - return fmt.Sprintf("operation failed (%x)", e.Result) -} - -// Request configuration -type Config struct { - // compute request MAC before sending - RequestMAC bool - // validate response MAC after receiving - ResponseMAC bool - // set Nonce field with random value - RandomNonce bool - // get response with a result read request - ResultRead bool -} - -// p98, Table 17 — Data Frame Files for RPMB, JESD84-B51 -type DataFrame struct { - StuffBytes [196]byte - KeyMAC [32]byte - Data [256]byte - Nonce [16]byte - WriteCounter [4]byte - Address [2]byte - BlockCount [2]byte - Result [2]byte - Resp byte - Req byte -} - -// Counter returns the data frame WriteCounter in uint32 format. -func (d *DataFrame) Counter() uint32 { - return binary.BigEndian.Uint32(d.WriteCounter[:]) -} - -// Bytes converts the data frame structure to byte array format. -func (d *DataFrame) Bytes() []byte { - buf := new(bytes.Buffer) - binary.Write(buf, binary.LittleEndian, d) - return buf.Bytes() -} - -func (p *RPMB) op(req *DataFrame, cfg *Config) (res *DataFrame, err error) { - var rel bool - - p.Lock() - defer p.Unlock() - - if !p.init { - return nil, errors.New("RPMB instance not initialized") - } - - mac := hmac.New(sha256.New, p.key[:]) - - if cfg.RequestMAC { - mac.Write(req.Bytes()[FrameLength-macOffset:]) - copy(req.KeyMAC[:], mac.Sum(nil)) - mac.Reset() - } - - if cfg.RandomNonce { - copy(req.Nonce[:], rng(len(req.Nonce))) - } - - switch req.Req { - case AuthenticationKeyProgramming, AuthenticatedDataWrite, AuthenticatedDeviceConfigurationWrite: - rel = true - default: - rel = false - } - - // send request - if err = p.card.WriteRPMB(req.Bytes(), rel); err != nil { - return - } - - // read result when required - if cfg.ResultRead { - resReq := DataFrame{ - Req: ResultRead, - } - - // send result read request - if err = p.card.WriteRPMB(resReq.Bytes(), false); err != nil { - return - } - } - - buf := make([]byte, FrameLength) - res = &DataFrame{} - - // read response - if err = p.card.ReadRPMB(buf); err != nil { - return - } - - // parse response - if err = binary.Read(bytes.NewReader(buf), binary.LittleEndian, res); err != nil { - return - } - - // validate response - - if cfg.ResponseMAC { - mac.Write(buf[FrameLength-macOffset:]) - - if !hmac.Equal(res.KeyMAC[:], mac.Sum(nil)) { - return nil, errors.New("invalid response MAC") - } - } - - if req.Req != res.Resp { - return nil, errors.New("request/response type mismatch") - } - - if req.Nonce != res.Nonce { - return nil, errors.New("nonce mismatch") - } - - result := binary.BigEndian.Uint16(res.Result[:]) - - if result != uint16(OperationOK) { - return nil, &OperationError{result} - } - - return -} - -func (p *RPMB) transfer(kind byte, offset uint16, buf []byte) (err error) { - if len(buf) > FrameLength/2 { - return errors.New("transfer size must not exceed 256 bytes") - } - - cfg := &Config{ - RequestMAC: true, - ResponseMAC: true, - } - - req := &DataFrame{ - Req: kind, - } - - if kind == AuthenticatedDataWrite { - counter, err := p.Counter(true) - - if err != nil { - return err - } - - binary.BigEndian.PutUint32(req.WriteCounter[:], counter) - - cfg.ResultRead = true - } else { - cfg.RandomNonce = true - } - - binary.BigEndian.PutUint16(req.BlockCount[:], 1) - binary.BigEndian.PutUint16(req.Address[:], offset) - copy(req.Data[:], buf) - - res, err := p.op(req, cfg) - - if err != nil { - return - } - - if kind == AuthenticatedDataRead { - copy(buf, res.Data[:]) - } else if res.Counter() != req.Counter()+1 { - return errors.New("write counter mismatch") - } - - return -} - -func rng(n int) []byte { - buf := make([]byte, n) - - if _, err := rand.Read(buf); err != nil { - log.Fatal(err) - } - - return buf -} diff --git a/rpmb/rpmb.go b/rpmb/rpmb.go deleted file mode 100644 index 47540d9..0000000 --- a/rpmb/rpmb.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2022 The Armored Witness OS authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package rpmb implements Replay Protected Memory Block (RPMB) configuration -// and control on eMMCs accessed through TamaGo NXP uSDHC driver. -// -// This package is only meant to be used with `GOOS=tamago GOARCH=arm` as -// supported by the TamaGo framework for bare metal Go on ARM SoCs, see -// https://github.com/usbarmory/tamago. -// -// The API supports mitigations for CVE-2020-13799 as described in the whitepaper linked at: -// -// https://www.westerndigital.com/support/productsecurity/wdc-20008-replay-attack-vulnerabilities-rpmb-protocol-applications -package rpmb - -import ( - "errors" - "fmt" - "sync" - - "github.com/usbarmory/tamago/soc/nxp/usdhc" -) - -const keyLen = 32 - -// RPMB defines a Replay Protected Memory Block partition access instance. -type RPMB struct { - sync.Mutex - - card *usdhc.USDHC - key [keyLen]byte - init bool -} - -// Init returns a new RPMB instance for a specific MMC card and MAC key. The -// dummyBlock argument is an unused sector, required for CVE-2020-13799 -// mitigation to invalidate uncommitted writes. -func Init(card *usdhc.USDHC, key []byte, dummyBlock uint16, writeDummy bool) (p *RPMB, err error) { - if card == nil { - return nil, fmt.Errorf("no MMC card set") - } - - if !card.Info().MMC { - return nil, fmt.Errorf("no MMC card detected") - } - - if len(key) != keyLen { - return nil, errors.New("invalid MAC key size") - } - - p = &RPMB{ - card: card, - init: true, - } - - copy(p.key[:], key) - - // invalidate uncommitted writes (CVE-2020-13799) if the RPMB has previously been programmed - if writeDummy { - if err = p.Write(dummyBlock, nil); err != nil { - return nil, err - } - } - - return -} - -// ProgramKey programs the RPMB partition authentication key. -// -// *WARNING*: this is a one-time irreversible operation for the specific MMC -// card associated to the RPMB partition instance. -func (p *RPMB) ProgramKey() (err error) { - cfg := &Config{ - ResultRead: true, - } - - req := &DataFrame{ - KeyMAC: p.key, - Req: AuthenticationKeyProgramming, - } - - _, err = p.op(req, cfg) - - return -} - -// Counter returns the RPMB partition write counter, the argument boolean -// indicates whether the read operation should be authenticated. -func (p *RPMB) Counter(auth bool) (n uint32, err error) { - cfg := &Config{ - RandomNonce: auth, - ResponseMAC: auth, - } - - req := &DataFrame{ - Req: WriteCounterRead, - } - - res, err := p.op(req, cfg) - - if err != nil { - return - } - - return res.Counter(), nil -} - -// Write performs an authenticated data transfer to the card RPMB partition, -// the input buffer can contain up to 256 bytes of data. -// -// The write operation mitigates CVE-2020-13799 by verifying that the response -// counter is equal to a single increment of the request counter, otherwise an -// error is returned. -func (p *RPMB) Write(offset uint16, buf []byte) (err error) { - return p.transfer(AuthenticatedDataWrite, offset, buf) -} - -// Read performs an authenticated data transfer from the card RPMB partition, -// the input buffer can contain up to 256 bytes of data. -func (p *RPMB) Read(offset uint16, buf []byte) (err error) { - return p.transfer(AuthenticatedDataRead, offset, buf) -} diff --git a/trusted_os/debug.go b/trusted_os/debug.go index 8d674db..f005644 100644 --- a/trusted_os/debug.go +++ b/trusted_os/debug.go @@ -179,7 +179,7 @@ func segfault(buf []byte, ctx *monitor.ExecCtx) (err error) { err = ctx.Run() - log.Printf("SM applet stopped sp:%#.8x lr:%#.8x pc:%#.8x err:%v", ctx.R13, ctx.R14, ctx.R15, err) + log.Printf("SM applet stopped sp:%#.8x lr:%#.8x pc:%#.8x err:%v %s", ctx.R13, ctx.R14, ctx.R15, err, ctx) return } diff --git a/trusted_os/load.go b/trusted_os/load.go index 1a9d3a3..9d87e31 100644 --- a/trusted_os/load.go +++ b/trusted_os/load.go @@ -66,7 +66,6 @@ func loadApplet(elf []byte, ctl *controlInterface) (ta *monitor.ExecCtx, err err // override default handler ta.Handler = handler - ta.Debug = true // enable FIQs bits.Clear(&ta.SPSR, CPSR_FIQ) @@ -101,7 +100,7 @@ func run(ctx *monitor.ExecCtx) (err error) { // when switching back to System Mode. imx6ul.ARM.EnableInterrupts(false) - log.Printf("SM applet stopped mode:%s sp:%#.8x lr:%#.8x pc:%#.8x ns:%v err:%v", mode, ctx.R13, ctx.R14, ctx.R15, ns, err) + log.Printf("SM applet stopped mode:%s sp:%#.8x lr:%#.8x pc:%#.8x ns:%v err:%v %s", mode, ctx.R13, ctx.R14, ctx.R15, ns, err, ctx) if err != nil && debug { err = inspect(taELF, ctx) diff --git a/trusted_os/main.go b/trusted_os/main.go index 29f60b1..acf706c 100644 --- a/trusted_os/main.go +++ b/trusted_os/main.go @@ -37,7 +37,6 @@ import ( // for now just test compilation of these "github.com/transparency-dev/armored-witness-common/release/firmware" _ "github.com/transparency-dev/armored-witness-os/internal/hab" - _ "github.com/transparency-dev/armored-witness-os/rpmb" ) const ( diff --git a/trusted_os/rpmb.go b/trusted_os/rpmb.go index 76eb536..571e632 100644 --- a/trusted_os/rpmb.go +++ b/trusted_os/rpmb.go @@ -29,13 +29,12 @@ import ( "golang.org/x/crypto/pbkdf2" + "github.com/usbarmory/rpmb" "github.com/usbarmory/tamago/soc/nxp/imx6ul" "github.com/usbarmory/tamago/soc/nxp/usdhc" "github.com/coreos/go-semver/semver" "github.com/usbarmory/crucible/otp" - - "github.com/transparency-dev/armored-witness-os/rpmb" ) const ( diff --git a/trusted_os/rpmb_fake.go b/trusted_os/rpmb_fake.go index b9866a6..14047b6 100644 --- a/trusted_os/rpmb_fake.go +++ b/trusted_os/rpmb_fake.go @@ -21,7 +21,7 @@ import ( "errors" "github.com/coreos/go-semver/semver" - "github.com/transparency-dev/armored-witness-os/rpmb" + "github.com/usbarmory/rpmb" ) const (