open-source-firmware / go-tcg-storage

Go library for interfacing TCG Storage functions on storage devices
BSD 3-Clause "New" or "Revised" License
21 stars 10 forks source link

"Locking" abstraction API #18

Open bluecmd opened 3 years ago

bluecmd commented 3 years ago

Goal: To hide the details about Enterprise / Opal / Ruby etc. and provide a way to access locking ranges both for administrative (enable, disable, modify) and for user (lock / unlock).

Suggestions:

github.com/bluecmd/go-tcg-storage/pkg/locking

locking.Initialize(d DriveIntf, adminAuth []locking.Authenticator, opts ...InitializeOpts) *ControlSession, SPID, error Ensures that the TPer is set up and has an enabled Locking SP. Returns the first available Locking SP and a ControlSession.

locking.NewSession(*ControlSession, SPID, auth locking.Authenticator, ..core.SessionOpts) *Locking, error Creates a new Locking session to the specified Locking SP with the given Authority credentials.

type LockingSP struct {
  Session *Session
  // All authorities that have been discovered on the SP.
  // This will likely be only the authenticated UID unless authorized as an Admin
  Authorities map[string]core.AuthorityObjectUID
  // The full range of Ranges (heh!) that the current session has access to see and possibly modify
  GlobalRange *Range
  Ranges []*Range // Ranges[0] == GlobalRange

  // These are always false on SSC Enterprise
  MBREnabled bool
  MBRDone bool
}

func (l *LockingSP) Close() error

func (l *LockingSP) SetAuthorityPIN(auth AuthorityObjectUID, pin []byte) error 

// ErrNotSupported on Enterprise
func (l *LockingSP) SetAuthorityEnabled(auth AuthorityObjectUID, enabled bool) error 

// Only Opal
func (l *LockingSP) SetMBRDone(v bool) error

// Only Opal
func (l *LockingSP) SetMBREnabled(v bool) error

type LockRange int
var LockRangeUnspecified LockRange = -1

type Range struct {
  l *Locking
  isGlobal bool

  UID RowUID
  // All known authoritiers that have access to lock/unlock on this range
  // Only populated with other users if authenticated as an Admin
  // For enterprise this will always be just one user, the band-dedicated BandMasterN for RangeN
  Users map[string]core.AuthorityObjectUID

  From LockRange
  To LockRange

  ReadLockEnabled bool
  WriteLockEnabled bool

  ReadLocked bool
  WriteLocked bool

  LockOnReset SomeType /* TODO */
}

func (r *Range) UnlockRead()  error
func (r *Range) LockRead()  error

func (r *Range) UnlockWrite()  error
func (r *Range) LockWrite()  error

func (r *Range) SetWriteLockEnabled(v bool)  error
func (r *Range) SetReadLockEnabled(v bool)  error

// Will fail if range is the Global Range
func (r *Range) SetRange(from LockRange, to LockRange)  error

func (r *Range) SetLockOnReset(.. /* todo */) error

// Only supported on SSC Enterprise probably
// Might be able to implement using GenKey (see "3.1.7 Erasing a range" in TCG Storage Application Note")
func (r *Range) Erase() error

// Grant access to specified user for this range
// Will fail with ErrNotSupported on Enterprise
func (r *Range) GrantUserAccess(auth AuthorityObjectUID) error
func (r *Range) RevokeUserAccess(auth AuthorityObjectUID) error

Example usage:

auth, ok := locking.AdminAuthoritySID([]byte{}) /* or */ locking.AuthorityFromName("admin1", []byte{})
// or 
auth, err := locking.DefaultAdminAuthority /* MSID */

cs, spid, err := locking.Initialize(d, 
    []Authenticator{auth},
    locking.WithHardening() /* enable hardening like FIPS mode */,
    locking.WithTakeOwnership([]byte{}) /* set the SID proof to given bytes */)
defer cs.Close()
l, err := locking.NewSession(cs, spid, auth, secret)
defer l.Close()

for _, r := range l.Ranges {
  r.UnlockRead()
  r.UnlockWrite()
}
r.SetMBRDone(true)

/* Change SID */
_, _, err := locking.Initialize(d, 
    []Authenticator{auth},
    locking.WithTakeOwnership(newSid) /* set the SID proof to given bytes */)
bluecmd commented 3 years ago

This has more or less been implemented now. The things left to do is the user/admin management stuff / ownership and lockdown.