github.com/linuxboot/fiano@v1.2.0/pkg/intel/metadata/bg/key.go (about)

     1  // Copyright 2017-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  //go:generate manifestcodegen
     6  
     7  package bg
     8  
     9  import (
    10  	"bytes"
    11  	"crypto"
    12  	"crypto/rsa"
    13  	"encoding/binary"
    14  	"fmt"
    15  	"math/big"
    16  )
    17  
    18  // Key is a public key of an asymmetric crypto keypair.
    19  type Key struct {
    20  	KeyAlg  Algorithm `json:"keyAlg"`
    21  	Version uint8     `require:"0x10"  json:"keyVersion"`
    22  	KeySize BitSize   `json:"keyBitsize"`
    23  	Data    []byte    `countValue:"keyDataSize()" json:"keyData"`
    24  }
    25  
    26  // BitSize is a size in bits.
    27  type BitSize uint16
    28  
    29  // InBits returns the size in bits.
    30  func (ks BitSize) InBits() uint16 {
    31  	return uint16(ks)
    32  }
    33  
    34  // InBytes returns the size in bytes.
    35  func (ks BitSize) InBytes() uint16 {
    36  	return uint16(ks >> 3)
    37  }
    38  
    39  // SetInBits sets the size in bits.
    40  func (ks *BitSize) SetInBits(amountOfBits uint16) {
    41  	*ks = BitSize(amountOfBits)
    42  }
    43  
    44  // SetInBytes sets the size in bytes.
    45  func (ks *BitSize) SetInBytes(amountOfBytes uint16) {
    46  	*ks = BitSize(amountOfBytes << 3)
    47  }
    48  
    49  // keyDataSize returns the expected length of Data for specified
    50  // KeyAlg and KeySize.
    51  func (k Key) keyDataSize() int64 {
    52  	switch k.KeyAlg {
    53  	case AlgRSA:
    54  		return int64(k.KeySize.InBytes()) + 4
    55  	}
    56  	return -1
    57  }
    58  
    59  // PubKey parses Data into crypto.PublicKey.
    60  func (k Key) PubKey() (crypto.PublicKey, error) {
    61  	expectedSize := int(k.keyDataSize())
    62  	if expectedSize < 0 {
    63  		return nil, fmt.Errorf("unexpected algorithm: %s", k.KeyAlg)
    64  	}
    65  	if len(k.Data) != expectedSize {
    66  		return nil, fmt.Errorf("unexpected size: expected:%d, received %d", expectedSize, len(k.Data))
    67  	}
    68  
    69  	switch k.KeyAlg {
    70  	case AlgRSA:
    71  		result := &rsa.PublicKey{
    72  			N: new(big.Int).SetBytes(reverseBytes(k.Data[4:])),
    73  			E: int(binaryOrder.Uint32(k.Data)),
    74  		}
    75  		return result, nil
    76  	}
    77  
    78  	return nil, fmt.Errorf("unexpected TPM algorithm: %s", k.KeyAlg)
    79  }
    80  
    81  func reverseBytes(b []byte) []byte {
    82  	r := make([]byte, len(b))
    83  	for idx := range b {
    84  		r[idx] = b[len(b)-idx-1]
    85  	}
    86  	return r
    87  }
    88  
    89  // SetPubKey sets Data the value corresponding to passed `key`.
    90  func (k *Key) SetPubKey(key crypto.PublicKey) error {
    91  	k.Version = 0x10
    92  
    93  	switch key := key.(type) {
    94  	case *rsa.PublicKey:
    95  		k.KeyAlg = AlgRSA
    96  		n := key.N.Bytes()
    97  		k.KeySize.SetInBytes(uint16(len(n)))
    98  		k.Data = make([]byte, 4+len(n))
    99  		binaryOrder.PutUint32(k.Data, uint32(key.E))
   100  		copy(k.Data[4:], reverseBytes(n))
   101  		return nil
   102  	}
   103  
   104  	return fmt.Errorf("unexpected key type: %T", key)
   105  }
   106  
   107  // PrintBPMPubKey prints the BPM public signing key hash to fuse into the Intel ME
   108  func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error {
   109  	buf := new(bytes.Buffer)
   110  	if len(k.Data) > 1 {
   111  		hash, err := bpmAlg.Hash()
   112  		if err != nil {
   113  			return err
   114  		}
   115  		if k.KeyAlg == AlgRSA {
   116  			if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil {
   117  				return err
   118  			}
   119  			hash.Write(buf.Bytes())
   120  			fmt.Printf("   Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
   121  		} else {
   122  			fmt.Printf("   Boot Policy Manifest Pubkey Hash: Unknown Algorithm\n")
   123  		}
   124  	} else {
   125  		fmt.Printf("   Boot Policy Pubkey Hash: No km public key set in KM\n")
   126  	}
   127  
   128  	return nil
   129  }
   130  
   131  // PrintKMPubKey prints the KM public signing key hash to fuse into the Intel ME
   132  func (k *Key) PrintKMPubKey(kmAlg Algorithm) error {
   133  	buf := new(bytes.Buffer)
   134  	if len(k.Data) > 1 {
   135  		if k.KeyAlg == AlgRSA {
   136  			if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil {
   137  				return err
   138  			}
   139  			if err := binary.Write(buf, binary.LittleEndian, k.Data[:4]); err != nil {
   140  				return err
   141  			}
   142  			if kmAlg != AlgSHA256 {
   143  				return fmt.Errorf("KM public key hash algorithm must be SHA256")
   144  			}
   145  			hash, err := kmAlg.Hash()
   146  			if err != nil {
   147  				return err
   148  			}
   149  			hash.Write(buf.Bytes())
   150  			fmt.Printf("   Key Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
   151  			// On SKL and KBL the exponent is not included in the KM hash
   152  			buf.Truncate(len(k.Data[4:]))
   153  			hash.Reset()
   154  			hash.Write(buf.Bytes())
   155  			fmt.Printf("   Key Manifest Pubkey Hash (Skylake and Kabylake only): 0x%x\n", hash.Sum(nil))
   156  		} else {
   157  			fmt.Printf("   Key Manifest Pubkey Hash: Unsupported Algorithm\n")
   158  		}
   159  	} else {
   160  		fmt.Printf("   Key Manifest Pubkey Hash: No km public key set in KM\n")
   161  	}
   162  
   163  	return nil
   164  }