github.com/transparency-dev/armored-witness-os@v0.1.3-0.20240514084412-27eef7325168/trusted_os/rpmb_fake.go (about)

     1  // Copyright 2022 The Armored Witness OS authors. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build fake_rpmb
    16  // +build fake_rpmb
    17  
    18  package main
    19  
    20  import (
    21  	"errors"
    22  
    23  	"github.com/coreos/go-semver/semver"
    24  	"github.com/transparency-dev/armored-witness-os/rpmb"
    25  )
    26  
    27  const (
    28  	// version epoch length
    29  	versionLength = 32
    30  	// RPMB sector for OS rollback protection
    31  	osVersionSector = 1
    32  	// RPMB sector for TA rollback protection
    33  	taVersionSector = 2
    34  
    35  	// RPMB sector for TA use
    36  	taUserSector = 3
    37  
    38  	sectorLength = 256
    39  	numSectors   = 16
    40  )
    41  
    42  type RPMB struct {
    43  	mem     [numSectors][sectorLength]byte
    44  	counter uint32
    45  }
    46  
    47  func newRPMB(_ Card) (*RPMB, error) {
    48  	return &RPMB{
    49  		mem: [numSectors][sectorLength]byte{},
    50  	}, nil
    51  }
    52  
    53  func (r *RPMB) init() error {
    54  	return nil
    55  }
    56  
    57  func parseVersion(s string) (version *semver.Version, err error) {
    58  	return semver.NewVersion(s)
    59  }
    60  
    61  // expectedVersion returns the version epoch stored in a fake RPMB area.
    62  func (r *RPMB) expectedVersion(offset uint16) (*semver.Version, error) {
    63  	v := string(r.mem[offset][:versionLength])
    64  
    65  	return semver.NewVersion(v)
    66  }
    67  
    68  // updateVersion writes a new version epoch in a fake RPMB area.
    69  func (r *RPMB) updateVersion(offset uint16, version semver.Version) error {
    70  	copy(r.mem[offset][:], []byte(version.String()))
    71  	r.counter++
    72  
    73  	return nil
    74  }
    75  
    76  // checkVersion verifies version information against RPMB stored data.
    77  //
    78  // If the passed version is older than the RPMB area information of the
    79  // internal eMMC an error is returned.
    80  //
    81  // If the passed version is more recent than the RPMB area information then the
    82  // internal eMMC is updated with it.
    83  func (r *RPMB) checkVersion(offset uint16, s string) error {
    84  	runningVersion, err := parseVersion(s)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	expectedVersion, err := r.expectedVersion(offset)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	switch {
    95  	case runningVersion.LessThan(*expectedVersion):
    96  		return errors.New("version mismatch")
    97  	case expectedVersion.Equal(*runningVersion):
    98  		return nil
    99  	case expectedVersion.LessThan(*runningVersion):
   100  		return r.updateVersion(offset, *runningVersion)
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  // transfer performs a data transfer to the fake RPMB area,
   107  // the input buffer can contain up to 256 bytes of data, n can be passed to
   108  // retrieve the write counter.
   109  func (r *RPMB) transfer(sector uint16, buf []byte, n *uint32, write bool) (err error) {
   110  	if len(buf) > rpmb.FrameLength/2 {
   111  		return errors.New("transfer size must not exceed 256 bytes")
   112  	}
   113  
   114  	if write {
   115  		copy(r.mem[sector][:], buf)
   116  		r.counter++
   117  	} else {
   118  		copy(buf, r.mem[sector][:])
   119  	}
   120  
   121  	if n != nil {
   122  		*n = r.counter
   123  	}
   124  	return
   125  }