Skip to content

Commit

Permalink
Version is a SemVer string (#194)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCutter authored Feb 26, 2024
1 parent 7433382 commit 437d6d3
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 81 deletions.
3 changes: 1 addition & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package api
import (
"bytes"
"fmt"
"time"

"google.golang.org/protobuf/proto"

Expand Down Expand Up @@ -98,7 +97,7 @@ func (p *Status) Print() string {
status.WriteString(fmt.Sprintf("Secure Boot ................: %v\n", p.HAB))
status.WriteString(fmt.Sprintf("SRK hash ...................: %s\n", p.SRKHash))
status.WriteString(fmt.Sprintf("Revision ...................: %s\n", p.Revision))
status.WriteString(fmt.Sprintf("Version ....................: %d (%s)\n", p.Version, time.Unix(int64(p.Version), 0)))
status.WriteString(fmt.Sprintf("Version ....................: %s\n", p.Version))
status.WriteString(fmt.Sprintf("Runtime ....................: %s\n", p.Runtime))
status.WriteString(fmt.Sprintf("Link .......................: %v\n", p.Link))
status.WriteString(fmt.Sprintf("IdentityCounter ............: %d\n", p.IdentityCounter))
Expand Down
8 changes: 4 additions & 4 deletions api/api.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ message Status {
bool HAB = 2;
string Revision = 3;
string Build = 4;
uint32 Version = 5;
string Version = 5;
string Runtime = 6;
bool Link = 7;
WitnessStatus Witness = 8;
Expand Down
10 changes: 8 additions & 2 deletions trusted_os/ctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,21 @@ type controlInterface struct {
}

func getStatus() (s *api.Status) {
version, _ := parseVersion(Version)
version, err := parseVersion(Version)
versionString := "unknown"
if err != nil {
log.Printf("failed to get version: %v", err)
} else {
versionString = version.String()
}

s = &api.Status{
Serial: fmt.Sprintf("%X", imx6ul.UniqueID()),
HAB: imx6ul.SNVS.Available(),
SRKHash: SRKHash,
Revision: Revision,
Build: Build,
Version: version,
Version: versionString,
Runtime: fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH),
// TODO(jayhou): set IdentityCounter here.
}
Expand Down
65 changes: 30 additions & 35 deletions trusted_os/rpmb.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ import (
"bytes"
"crypto/aes"
"crypto/sha256"
"encoding/binary"
"encoding/gob"
"errors"
"fmt"
"log"
"strconv"

"golang.org/x/crypto/pbkdf2"

"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"
Expand All @@ -41,7 +41,7 @@ const (
// RPMB sector for CVE-2020-13799 mitigation
dummySector = 0
// version epoch length
versionLength = 4
versionLength = 32
// RPMB sector for OS rollback protection
osVersionSector = 1
// RPMB sector for TA rollback protection
Expand Down Expand Up @@ -144,43 +144,40 @@ func (r *RPMB) init() error {
return nil
}

func parseVersion(s string) (version uint32, err error) {
v, err := strconv.Atoi(s)

if err != nil {
return
}

return uint32(v), nil
func parseVersion(s string) (version *semver.Version, err error) {
return semver.NewVersion(s)
}

// expectedVersion returns the version epoch stored in an RPMB area of the
// internal eMMC.
func (r *RPMB) expectedVersion(offset uint16) (version uint32, err error) {
func (r *RPMB) expectedVersion(offset uint16) (*semver.Version, error) {
if r.partition == nil {
return 0, errors.New("RPMB has not been initialized")
return nil, errors.New("RPMB has not been initialized")
}

buf := make([]byte, versionLength)

if err = r.partition.Read(offset, buf); err != nil {
return
if err := r.partition.Read(offset, buf); err != nil {
return nil, err
}
var v string
if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(&v); err != nil {
return nil, err
}

return binary.BigEndian.Uint32(buf), nil
return semver.NewVersion(v)
}

// updateVersion writes a new version epoch in an RPMB area of the internal
// eMMC.
func (r *RPMB) updateVersion(offset uint16, version uint32) (err error) {
func (r *RPMB) updateVersion(offset uint16, version semver.Version) error {
if r.partition == nil {
return errors.New("RPMB has not been initialized")
}

buf := make([]byte, versionLength)
binary.BigEndian.PutUint32(buf, version)

return r.partition.Write(offset, buf)
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(version.String()); err != nil {
return err
}
return r.partition.Write(offset, buf.Bytes())
}

// checkVersion verifies version information against RPMB stored data.
Expand All @@ -190,29 +187,27 @@ func (r *RPMB) updateVersion(offset uint16, version uint32) (err error) {
//
// If the passed version is more recent than the RPMB area information then the
// internal eMMC is updated with it.
func (r *RPMB) checkVersion(offset uint16, s string) (err error) {
version, err := parseVersion(s)

func (r *RPMB) checkVersion(offset uint16, s string) error {
runningVersion, err := parseVersion(s)
if err != nil {
return
return err
}

expectedVersion, err := r.expectedVersion(offset)

if err != nil {
return
return err
}

switch {
case expectedVersion > version:
case runningVersion.LessThan(*expectedVersion):
return errors.New("version mismatch")
case expectedVersion == version:
return
case expectedVersion < version:
return r.updateVersion(offset, version)
case expectedVersion.Equal(*runningVersion):
return nil
case expectedVersion.LessThan(*runningVersion):
return r.updateVersion(offset, *runningVersion)
}

return
return nil
}

// transfer performs an authenticated data transfer to the card RPMB partition,
Expand Down
62 changes: 25 additions & 37 deletions trusted_os/rpmb_fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@
package main

import (
"encoding/binary"
"errors"
"strconv"

"github.com/coreos/go-semver/semver"
"github.com/transparency-dev/armored-witness-os/rpmb"
)

const (
// version epoch length
versionLength = 4
versionLength = 32
// RPMB sector for OS rollback protection
osVersionSector = 1
// RPMB sector for TA rollback protection
Expand All @@ -47,72 +46,61 @@ type RPMB struct {

func newRPMB(_ Card) (*RPMB, error) {
return &RPMB{
mem: make(map[numSectors][sectorLength]byte),
mem: [numSectors][sectorLength]byte{},
}, nil
}

func r (*RPMB) init() error {
func (r *RPMB) init() error {
return nil
}

func parseVersion(s string) (version uint32, err error) {
v, err := strconv.Atoi(s)
if err != nil {
return
}

return uint32(v), nil
func parseVersion(s string) (version *semver.Version, err error) {
return semver.NewVersion(s)
}

// expectedVersion returns the version epoch stored in a fake RPMB area.
func (r *RPMB) expectedVersion(sector uint16) (version uint32, err error) {
buf := make([]byte, versionLength)
copy(buf, r.mem[sector])
func (r *RPMB) expectedVersion(offset uint16) (*semver.Version, error) {
v := string(r.mem[offset][:versionLength])

return binary.BigEndian.Uint32(buf), nil
return semver.NewVersion(v)
}

// updateVersion writes a new version epoch in a fake RPMB area.
func (r *RPMB) updateVersion(sector uint16, version uint32) (err error) {
buf := make([]byte, versionLength)
binary.BigEndian.PutUint32(buf, version)

copy(r.mem[sector], buf)
func (r *RPMB) updateVersion(offset uint16, version semver.Version) error {
copy(r.mem[offset][:], []byte(version.String()))
r.counter++

return nil
}

// checkVersion verifies version information against fake RPMB stored data.
// checkVersion verifies version information against RPMB stored data.
//
// If the passed version is older than the RPMB area information of the
// internal eMMC an error is returned.
//
// If the passed version is more recent than the RPMB area information then the
// internal eMMC is updated with it.
func (r *RPMB) checkVersion(sector uint16, s string) (err error) {
version, err := parseVersion(s)

func (r *RPMB) checkVersion(offset uint16, s string) error {
runningVersion, err := parseVersion(s)
if err != nil {
return
return err
}

expectedVersion, err := r.expectedVersion(sector)

expectedVersion, err := r.expectedVersion(offset)
if err != nil {
return
return err
}

switch {
case expectedVersion > version:
case runningVersion.LessThan(*expectedVersion):
return errors.New("version mismatch")
case expectedVersion == version:
return
case expectedVersion < version:
return r.updateVersion(sector, version)
case expectedVersion.Equal(*runningVersion):
return nil
case expectedVersion.LessThan(*runningVersion):
return r.updateVersion(offset, *runningVersion)
}

return
return nil
}

// transfer performs a data transfer to the fake RPMB area,
Expand All @@ -124,10 +112,10 @@ func (r *RPMB) transfer(sector uint16, buf []byte, n *uint32, write bool) (err e
}

if write {
copy(r.mem[sector], buf)
copy(r.mem[sector][:], buf)
r.counter++
} else {
copy(buf, r.mem[sector])
copy(buf, r.mem[sector][:])
}

if n != nil {
Expand Down

0 comments on commit 437d6d3

Please sign in to comment.