github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/keys.go (about)

     1  // Copyright 2023 the LinuxBoot Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package psb
     6  
     7  // Key parsing logic is based on AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h and Family 19h Processors
     8  // Publication # 55758
     9  // Issue Date: August 2020
    10  // Revision: 1.11
    11  
    12  import (
    13  	"bytes"
    14  	"crypto/rsa"
    15  	"encoding/binary"
    16  	"errors"
    17  	"fmt"
    18  	"math/big"
    19  
    20  	"strings"
    21  
    22  	amd_manifest "github.com/linuxboot/fiano/pkg/amd/manifest"
    23  )
    24  
    25  // KeyID is the primary identifier of a key
    26  type KeyID Buf16B
    27  
    28  // Hex returns a hexadecimal string representation of a KeyID
    29  func (kid *KeyID) Hex() string {
    30  	var s strings.Builder
    31  	fmt.Fprintf(&s, "%x", *kid)
    32  	return s.String()
    33  }
    34  
    35  // String returns the hexadecimal string representation of a KeyID
    36  func (kid *KeyID) String() string {
    37  	return kid.Hex()
    38  }
    39  
    40  // KeyIDs represents a list of KeyID
    41  type KeyIDs []KeyID
    42  
    43  // String returns a string representation of all KeyIDs
    44  func (kids KeyIDs) String() string {
    45  	if len(kids) == 0 {
    46  		return ""
    47  	}
    48  
    49  	var s strings.Builder
    50  	fmt.Fprintf(&s, "%s", kids[0].Hex())
    51  	for _, kid := range kids[1:] {
    52  		fmt.Fprintf(&s, ", %s", kid.Hex())
    53  	}
    54  	return s.String()
    55  }
    56  
    57  // KeyUsageFlag describes a known values for KeyUsageFlag field of AMD PSP Key structure
    58  type KeyUsageFlag uint32
    59  
    60  const (
    61  	// SignAMDBootloaderPSPSMU tells that the corresponding key is authorized to sign AMD developed PSP Boot
    62  	// Loader and AMD developed PSP FW components and SMU FW.
    63  	// See Table 26. RSA Key Format Fields of AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h and 19h Processors
    64  	// Revision 1.11
    65  	SignAMDBootloaderPSPSMU KeyUsageFlag = 0
    66  
    67  	// SignBIOS tells that the corresponding key is authorized to sign BIOS
    68  	SignBIOS KeyUsageFlag = 1
    69  
    70  	// SignAMDOEMPSP tells that the corresponding key is authorized to sign PSP FW (both AMD developed and OEM developed)
    71  	SignAMDOEMPSP KeyUsageFlag = 2
    72  
    73  	// PSBSignBIOS tells that a key is authorized to sign BIOS for platform secure boot.
    74  	// See Table 8. RSA Key Format Fields of Enabling Platform Secure Boot
    75  	// for AMD Family 17h Models 00h–0Fh and 30h–3Fh and Family 19h Models 00h–0Fh Processor-Based Server Platforms
    76  	// Revision 0.91
    77  	PSBSignBIOS KeyUsageFlag = 8
    78  )
    79  
    80  // KeyData represents the binary format (as it is stored in an image) of the information associated with a key
    81  type KeyData struct {
    82  	VersionID       uint32
    83  	KeyID           KeyID
    84  	CertifyingKeyID Buf16B
    85  	KeyUsageFlag    KeyUsageFlag
    86  	Reserved        Buf16B
    87  	ExponentSize    uint32
    88  	ModulusSize     uint32
    89  	Exponent        []byte
    90  	Modulus         []byte
    91  }
    92  
    93  // Key structure extracted from the firmware
    94  type Key struct {
    95  	data KeyData
    96  }
    97  
    98  // PlatformBindingInfo describes information of BIOS Signing Key to Platform Binding information
    99  type PlatformBindingInfo struct {
   100  	VendorID        uint8
   101  	KeyRevisionID   uint8
   102  	PlatformModelID uint8
   103  }
   104  
   105  func (b PlatformBindingInfo) String() string {
   106  	var s strings.Builder
   107  	fmt.Fprintf(&s, "Vendor ID: %X\n", b.VendorID)
   108  	fmt.Fprintf(&s, "Key Revision ID: %X\n", b.KeyRevisionID)
   109  	fmt.Fprintf(&s, "Platform Model ID: %X\n", b.PlatformModelID)
   110  	return s.String()
   111  }
   112  
   113  // GetPlatformBindingInfo for PSBSignBIOS key returns BIOS Signing Key to Platform Binding information
   114  func GetPlatformBindingInfo(k *Key) (PlatformBindingInfo, error) {
   115  	if k.data.KeyUsageFlag != PSBSignBIOS {
   116  		return PlatformBindingInfo{}, fmt.Errorf("not a PSBSignBios key usage flag: %v", k.data.KeyUsageFlag)
   117  	}
   118  	return parsePlatformBinding(k.data.Reserved), nil
   119  }
   120  
   121  func parsePlatformBinding(reserved Buf16B) PlatformBindingInfo {
   122  	return PlatformBindingInfo{
   123  		VendorID:        reserved[0],
   124  		KeyRevisionID:   reserved[1] & 7,  // Bits 0:3 => Key Revision ID
   125  		PlatformModelID: reserved[1] << 3, // Bits 4:7 => Platform Model ID
   126  	}
   127  }
   128  
   129  // SecurityFeatureVector represents a security feature selection vector of BIOS OEM key
   130  type SecurityFeatureVector struct {
   131  	DisableBIOSKeyAntiRollback bool
   132  	DisableAMDBIOSKeyUse       bool
   133  	DisableSecureDebugUnlock   bool
   134  }
   135  
   136  func (sfv SecurityFeatureVector) String() string {
   137  	var s strings.Builder
   138  	fmt.Fprintf(&s, "DISABLE_BIOS_KEY_ANTI_ROLLBACK: %t\n", sfv.DisableBIOSKeyAntiRollback)
   139  	fmt.Fprintf(&s, "DISABLE_AMD_BIOS_KEY_USE: %t\n", sfv.DisableAMDBIOSKeyUse)
   140  	fmt.Fprintf(&s, "DISABLE_SECURE_DEBUG_UNLOCK: %t\n", sfv.DisableSecureDebugUnlock)
   141  	return s.String()
   142  }
   143  
   144  // GetSecurityFeatureVector for PSBSignBIOS key returns a security feature selection vector
   145  func GetSecurityFeatureVector(k *Key) (SecurityFeatureVector, error) {
   146  	if k.data.KeyUsageFlag != PSBSignBIOS {
   147  		return SecurityFeatureVector{}, fmt.Errorf("not a PSBSignBios key usage flag: %v", k.data.KeyUsageFlag)
   148  	}
   149  	return parseSecurityFeatureVector(k.data.Reserved), nil
   150  }
   151  
   152  func parseSecurityFeatureVector(reserved Buf16B) SecurityFeatureVector {
   153  	return SecurityFeatureVector{
   154  		DisableBIOSKeyAntiRollback: reserved[3]&1 == 1,
   155  		DisableAMDBIOSKeyUse:       (reserved[3]<<1)&1 == 1,
   156  		DisableSecureDebugUnlock:   (reserved[3]<<2)&1 == 1,
   157  	}
   158  }
   159  
   160  // Key creation functions manage two slightly different key structures available in firmware:
   161  //
   162  // 1) Those serialized into key tokens
   163  // 2) Those serialized into the key database
   164  //
   165  // Format 2) is as follow:
   166  //
   167  // type key struct {
   168  // 		dataSize uint32
   169  //		version uint32
   170  //		keyUsageFlag uint32
   171  // 		publicExponent [4]uint8
   172  //		keyID	[16]uint8
   173  //		keySize uint32
   174  //		reserved Buf44B
   175  //		modulus []byte
   176  // }
   177  //
   178  // From a bytes buffer, there is no way to distinguish between the two cases above, so an indication
   179  // of which format to use should come from the caller (by calling NewKey<TYPE>).
   180  //
   181  // Both formats will be deserialized into Key structure. Some fields of Key might contain zero value
   182  // (e.g. certifying key ID for keys extracted from the key database, which is indirectly the AMD root
   183  // key as it signs the whole key database).
   184  //
   185  // If the key is a token key, the signature is validated.
   186  // Additional safety checks are implemented during serialization:
   187  // if a `certifyingKeyID` is retrieved from the buffer and it's not null, a KeySet must be available for validation,
   188  // or an error will be returned. Callers however are ultimately responsible to make sure that a KeySet is passed if
   189  // a key should be validated.
   190  
   191  func zeroCertifyingKeyID(key *Key) bool {
   192  	for _, v := range key.data.CertifyingKeyID {
   193  		if v != 0 {
   194  			return false
   195  		}
   196  	}
   197  	return true
   198  }
   199  
   200  // readExponent reads exponent value from a buffer, assuming exponent size
   201  // has already been populated.
   202  func readExponent(buff *bytes.Buffer, key *Key) error {
   203  	if key.data.ExponentSize%8 != 0 {
   204  		return newErrInvalidFormat(fmt.Errorf("exponent size is not divisible by 8"))
   205  	}
   206  	exponent := make([]byte, key.data.ExponentSize/8)
   207  	if err := binary.Read(buff, binary.LittleEndian, &exponent); err != nil {
   208  		return newErrInvalidFormat(fmt.Errorf("could not parse exponent: %w", err))
   209  	}
   210  	key.data.Exponent = exponent
   211  	return nil
   212  }
   213  
   214  // readModulus reads modulus value from a buffer, assuming modulus size
   215  // has already been populated
   216  func readModulus(buff *bytes.Buffer, key *Key) error {
   217  	if key.data.ModulusSize%8 != 0 {
   218  		return newErrInvalidFormat(fmt.Errorf("modulus size is not divisible by 8"))
   219  	}
   220  
   221  	modulus := make([]byte, key.data.ModulusSize/8)
   222  	if err := binary.Read(buff, binary.LittleEndian, &modulus); err != nil {
   223  		return newErrInvalidFormat(fmt.Errorf("could not parse modulus: %w", err))
   224  	}
   225  	key.data.Modulus = modulus
   226  	return nil
   227  }
   228  
   229  // newTokenOrRootKey creates the common parts of Token and Root keys
   230  func newTokenOrRootKey(buff *bytes.Buffer) (*Key, error) {
   231  
   232  	key := Key{}
   233  
   234  	if err := binary.Read(buff, binary.LittleEndian, &key.data.VersionID); err != nil {
   235  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse VersionID: %w", err))
   236  	}
   237  	if err := binary.Read(buff, binary.LittleEndian, &key.data.KeyID); err != nil {
   238  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse KeyID: %w", err))
   239  	}
   240  	if err := binary.Read(buff, binary.LittleEndian, &key.data.CertifyingKeyID); err != nil {
   241  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse Certifying KeyID: %w", err))
   242  	}
   243  	if err := binary.Read(buff, binary.LittleEndian, &key.data.KeyUsageFlag); err != nil {
   244  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse Key Usage Flag: %w", err))
   245  	}
   246  	if err := binary.Read(buff, binary.LittleEndian, &key.data.Reserved); err != nil {
   247  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse reserved area: %w", err))
   248  	}
   249  	if err := binary.Read(buff, binary.LittleEndian, &key.data.ExponentSize); err != nil {
   250  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse exponent size: %w", err))
   251  	}
   252  	if err := binary.Read(buff, binary.LittleEndian, &key.data.ModulusSize); err != nil {
   253  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse modulus size: %w", err))
   254  	}
   255  
   256  	if err := readExponent(buff, &key); err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	if err := readModulus(buff, &key); err != nil {
   261  		return nil, err
   262  	}
   263  	return &key, nil
   264  }
   265  
   266  // NewRootKey creates a new root key object which is considered trusted without any need for signature check
   267  func NewRootKey(buff *bytes.Buffer) (*Key, error) {
   268  	key, err := newTokenOrRootKey(buff)
   269  	if err != nil {
   270  		return nil, fmt.Errorf("cannot parse root key: %w", err)
   271  	}
   272  
   273  	if key.data.KeyID != key.data.CertifyingKeyID {
   274  		return nil, newErrInvalidFormat(fmt.Errorf("root key must have certifying key ID == key ID (key ID: %x, certifying key ID: %x)", key.data.KeyID, key.data.CertifyingKeyID))
   275  	}
   276  	return key, err
   277  
   278  }
   279  
   280  // NewTokenKey create a new key object from a signed token
   281  func NewTokenKey(buff *bytes.Buffer, keySet KeySet) (*Key, error) {
   282  
   283  	raw := buff.Bytes()
   284  
   285  	key, err := newTokenOrRootKey(buff)
   286  	if err != nil {
   287  		return nil, fmt.Errorf("could not create new token key: %w", err)
   288  	}
   289  
   290  	signingKeyID := KeyID(key.data.CertifyingKeyID)
   291  	signingKey := keySet.GetKey(signingKeyID)
   292  	if signingKey == nil {
   293  		return nil, fmt.Errorf("could not find signing key with ID %s for key token key", signingKeyID.Hex())
   294  	}
   295  
   296  	signatureSize, err := signingKey.SignatureSize()
   297  	if err != nil {
   298  		return nil, &SignatureCheckError{signingKey: signingKey, err: fmt.Errorf("could not get signature length of a key: %w", err)}
   299  	}
   300  
   301  	// validate the signature of the new token key
   302  	signature := make([]byte, signatureSize)
   303  	if err := binary.Read(buff, binary.LittleEndian, &signature); err != nil {
   304  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse signature from key token: %w", err))
   305  	}
   306  
   307  	// A key extracted from a signed token has the following structure:
   308  	// * 64 bytes header
   309  	// * exponent
   310  	// * modulus
   311  	// * signature.
   312  	//
   313  	// Exponent, modulus and signature are all of the same size. Only the latter is not signed, hence the length
   314  	// of the signed payload is header size + 2 * exponent/modulus size.
   315  	lenSigned := uint64(64 + 2*key.data.ModulusSize/8)
   316  	if uint64(len(raw)) < lenSigned {
   317  		return nil, newErrInvalidFormat(fmt.Errorf("length of signed token is not sufficient: expected > %d, got %d", lenSigned, len(raw)))
   318  	}
   319  
   320  	// Validate the signature of the raw token
   321  	if _, err := NewSignedBlob(reverse(signature), raw[:lenSigned], signingKey); err != nil {
   322  		return nil, fmt.Errorf("could not validate the signature of token key: %w", err)
   323  	}
   324  	return key, nil
   325  }
   326  
   327  // NewKeyFromDatabase creates a new key object from key database entry
   328  func NewKeyFromDatabase(buff *bytes.Buffer) (*Key, error) {
   329  	key := Key{}
   330  
   331  	var (
   332  		dataSize uint32
   333  		numRead  uint64
   334  	)
   335  
   336  	if err := readAndCountSize(buff, binary.LittleEndian, &dataSize, &numRead); err != nil {
   337  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse dataSize: %w", err))
   338  	}
   339  
   340  	// consider if we still have enough data to parse a whole key entry which is dataSize long.
   341  	// dataSize includes the uint32 dataSize field itself
   342  	if uint64(dataSize) > uint64(buff.Len())+4 {
   343  		return nil, newErrInvalidFormat(fmt.Errorf("buffer is not long enough (%d) to satisfy dataSize (%d)", buff.Len(), dataSize))
   344  	}
   345  
   346  	if err := readAndCountSize(buff, binary.LittleEndian, &key.data.VersionID, &numRead); err != nil {
   347  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse VersionID: %w", err))
   348  	}
   349  
   350  	if err := readAndCountSize(buff, binary.LittleEndian, &key.data.KeyUsageFlag, &numRead); err != nil {
   351  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse key usage flags: %w", err))
   352  	}
   353  
   354  	var publicExponent Buf4B
   355  	if err := readAndCountSize(buff, binary.LittleEndian, &publicExponent, &numRead); err != nil {
   356  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse public exponent: %w", err))
   357  	}
   358  	key.data.Exponent = publicExponent[:]
   359  
   360  	if err := readAndCountSize(buff, binary.LittleEndian, &key.data.KeyID, &numRead); err != nil {
   361  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse key id: %w", err))
   362  	}
   363  
   364  	var keySize uint32
   365  	if err := readAndCountSize(buff, binary.LittleEndian, &keySize, &numRead); err != nil {
   366  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse key size: %w", err))
   367  	}
   368  	if keySize == 0 {
   369  		return nil, newErrInvalidFormat(fmt.Errorf("key size cannot be 0"))
   370  	}
   371  
   372  	if keySize%8 != 0 {
   373  		return nil, newErrInvalidFormat(fmt.Errorf("key size is not divisible by 8 (%d)", keySize))
   374  	}
   375  
   376  	key.data.ExponentSize = keySize
   377  	key.data.ModulusSize = keySize
   378  
   379  	var reserved Buf44B
   380  	if err := readAndCountSize(buff, binary.LittleEndian, &reserved, &numRead); err != nil {
   381  		return nil, newErrInvalidFormat(fmt.Errorf("could not parse reserved area: %w", err))
   382  	}
   383  	// check if we have enough data left, based on keySize and dataSize
   384  	if (numRead + uint64(keySize)/8) > uint64(dataSize) {
   385  		return nil, newErrInvalidFormat(fmt.Errorf("inconsistent header, read so far %d, total size is %d, key size to read is %d, which goes out of bound", numRead, dataSize, keySize))
   386  	}
   387  
   388  	if err := readModulus(buff, &key); err != nil {
   389  		return nil, err
   390  	}
   391  
   392  	if !zeroCertifyingKeyID(&key) {
   393  		return nil, newErrInvalidFormat(fmt.Errorf("key extracted from key database should have zero certifying key ID"))
   394  	}
   395  
   396  	return &key, nil
   397  }
   398  
   399  // String returns a string representation of the key
   400  func (k *Key) String() string {
   401  	var s strings.Builder
   402  
   403  	pubKey, err := k.Get()
   404  	if err != nil {
   405  		fmt.Fprintf(&s, "could not get RSA key from raw bytes: %v\n", err)
   406  		return s.String()
   407  	}
   408  
   409  	fmt.Fprintf(&s, "Version ID: 0x%x\n", k.data.VersionID)
   410  	fmt.Fprintf(&s, "Key ID: 0x%s\n", k.data.KeyID.Hex())
   411  	fmt.Fprintf(&s, "Certifying Key ID: 0x%x\n", k.data.CertifyingKeyID)
   412  	fmt.Fprintf(&s, "Key Usage Flag: 0x%x\n", k.data.KeyUsageFlag)
   413  	if k.data.KeyUsageFlag == PSBSignBIOS {
   414  		fmt.Fprintf(&s, "%s", parsePlatformBinding(k.data.Reserved))
   415  		fmt.Fprintf(&s, "%s", parseSecurityFeatureVector(k.data.Reserved))
   416  	}
   417  	fmt.Fprintf(&s, "Exponent size: 0x%x (dec %d) \n", k.data.ExponentSize, k.data.ExponentSize)
   418  	fmt.Fprintf(&s, "Modulus size: 0x%x (dec %d)\n", k.data.ModulusSize, k.data.ModulusSize)
   419  
   420  	switch rsaKey := pubKey.(type) {
   421  	case *rsa.PublicKey:
   422  		fmt.Fprintf(&s, "Exponent: 0x%d\n", rsaKey.E)
   423  	default:
   424  		fmt.Fprintf(&s, "Exponent: key is not RSA, cannot get decimal exponent\n")
   425  	}
   426  
   427  	fmt.Fprintf(&s, "Modulus: 0x%x\n", k.data.Modulus)
   428  	return s.String()
   429  }
   430  
   431  // Get returns the PublicKey object from golang standard library.
   432  // AMD Milan supports only RSA Keys (2048, 4096), future platforms
   433  // might add support for additional key types.
   434  func (k *Key) Get() (interface{}, error) {
   435  	if err := k.checkValid(); err != nil {
   436  		return nil, err
   437  	}
   438  
   439  	N := big.NewInt(0)
   440  	E := big.NewInt(0)
   441  
   442  	// modulus and exponent are read as little endian
   443  	rsaPk := rsa.PublicKey{N: N.SetBytes(reverse(k.data.Modulus)), E: int(E.SetBytes(reverse(k.data.Exponent)).Int64())}
   444  	return &rsaPk, nil
   445  }
   446  
   447  // SignatureSize returns the size of the signature
   448  func (k *Key) SignatureSize() (int, error) {
   449  	if err := k.checkValid(); err != nil {
   450  		return 0, err
   451  	}
   452  	return len(k.data.Modulus), nil
   453  }
   454  
   455  func (k *Key) checkValid() error {
   456  	if len(k.data.Exponent) == 0 {
   457  		return fmt.Errorf("invalid key: exponent size is 0")
   458  	}
   459  	if len(k.data.Modulus) == 0 {
   460  		return fmt.Errorf("invalid key: modulus size is 0")
   461  	}
   462  	return nil
   463  }
   464  
   465  // GetKeys returns all the keys known to the system in the form of a KeySet.
   466  // The firmware itself contains a key database, but that is not comprehensive
   467  // of all the keys known to the system (e.g. additional keys might be OEM key,
   468  // ABL signing key, etc.).
   469  func GetKeys(amdFw *amd_manifest.AMDFirmware, level uint) (KeySet, error) {
   470  	keySet := NewKeySet()
   471  	err := getKeysFromDatabase(amdFw, level, keySet)
   472  	if err != nil {
   473  		return keySet, fmt.Errorf("could not get key from table into KeySet: %w", err)
   474  	}
   475  
   476  	// Extract ABL signing key (entry 0x0A in PSP Directory), which is signed with AMD Public Key.
   477  	pubKeyBytes, err := ExtractPSPEntry(amdFw, level, ABLPublicKey)
   478  	if err != nil {
   479  		return keySet, fmt.Errorf("could not extract raw PSP entry for ABL Public Key: %w", err)
   480  	}
   481  	ablPk, err := NewTokenKey(bytes.NewBuffer(pubKeyBytes), keySet)
   482  	if err != nil {
   483  		return keySet, addFirmwareItemToError(err, newPSPDirectoryEntryItem(uint8(level), ABLPublicKey))
   484  	}
   485  
   486  	err = keySet.AddKey(ablPk, ABLKey)
   487  	if err != nil {
   488  		return keySet, fmt.Errorf("could not add ABL signing key to key set: %w", err)
   489  	}
   490  
   491  	// Extract OEM signing key (entry 0x05 in BIOS Directory table)
   492  	// in PSB disabled this entry doesn't exist
   493  	pubKeyBytes, err = ExtractBIOSEntry(amdFw, level, OEMSigningKeyEntry, 0)
   494  	if err != nil {
   495  		if !errors.As(err, &ErrNotFound{}) {
   496  			return keySet, fmt.Errorf("could not extract raw BIOS directory entry for OEM Public Key: %w", err)
   497  		}
   498  	} else {
   499  		oemPk, err := NewTokenKey(bytes.NewBuffer(pubKeyBytes), keySet)
   500  		if err != nil {
   501  			return keySet, fmt.Errorf("could not extract OEM public key: %w", err)
   502  		}
   503  
   504  		err = keySet.AddKey(oemPk, OEMKey)
   505  		if err != nil {
   506  			return keySet, fmt.Errorf("could not add OEM signing key to key set: %w", err)
   507  		}
   508  	}
   509  	return keySet, nil
   510  }