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

     1  // Copyright 2017-2021 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 cbnt
     8  
     9  import (
    10  	"bytes"
    11  	"crypto"
    12  	"crypto/ecdsa"
    13  	"crypto/elliptic"
    14  	"crypto/rsa"
    15  	"encoding/binary"
    16  	"fmt"
    17  	"math/big"
    18  
    19  	"github.com/tjfoc/gmsm/sm2"
    20  )
    21  
    22  // Key is a public key of an asymmetric crypto keypair.
    23  type Key struct {
    24  	KeyAlg  Algorithm `json:"keyAlg"`
    25  	Version uint8     `require:"0x10"  json:"keyVersion"`
    26  	KeySize BitSize   `json:"keyBitsize"`
    27  	Data    []byte    `countValue:"keyDataSize()" json:"keyData"`
    28  }
    29  
    30  // BitSize is a size in bits.
    31  type BitSize uint16
    32  
    33  // InBits returns the size in bits.
    34  func (ks BitSize) InBits() uint16 {
    35  	return uint16(ks)
    36  }
    37  
    38  // InBytes returns the size in bytes.
    39  func (ks BitSize) InBytes() uint16 {
    40  	return uint16(ks >> 3)
    41  }
    42  
    43  // SetInBits sets the size in bits.
    44  func (ks *BitSize) SetInBits(amountOfBits uint16) {
    45  	*ks = BitSize(amountOfBits)
    46  }
    47  
    48  // SetInBytes sets the size in bytes.
    49  func (ks *BitSize) SetInBytes(amountOfBytes uint16) {
    50  	*ks = BitSize(amountOfBytes << 3)
    51  }
    52  
    53  // keyDataSize returns the expected length of Data for specified
    54  // KeyAlg and KeySize.
    55  func (k Key) keyDataSize() int64 {
    56  	switch k.KeyAlg {
    57  	case AlgRSA:
    58  		return int64(k.KeySize.InBytes()) + 4
    59  	case AlgECC, AlgSM2:
    60  		return int64(k.KeySize.InBytes()) * 2
    61  	}
    62  	return -1
    63  }
    64  
    65  // PubKey parses Data into crypto.PublicKey.
    66  func (k Key) PubKey() (crypto.PublicKey, error) {
    67  	expectedSize := int(k.keyDataSize())
    68  	if expectedSize < 0 {
    69  		return nil, fmt.Errorf("unexpected algorithm: %s", k.KeyAlg)
    70  	}
    71  	if len(k.Data) != expectedSize {
    72  		return nil, fmt.Errorf("unexpected size: expected:%d, received %d", expectedSize, len(k.Data))
    73  	}
    74  
    75  	switch k.KeyAlg {
    76  	case AlgRSA:
    77  		result := &rsa.PublicKey{
    78  			N: new(big.Int).SetBytes(reverseBytes(k.Data[4:])),
    79  			E: int(binaryOrder.Uint32(k.Data)),
    80  		}
    81  		return result, nil
    82  	case AlgECC:
    83  		keySize := k.KeySize.InBytes()
    84  		x := new(big.Int).SetBytes(reverseBytes(k.Data[:keySize]))
    85  		y := new(big.Int).SetBytes(reverseBytes(k.Data[keySize:]))
    86  		return ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
    87  	case AlgSM2:
    88  		keySize := k.KeySize.InBytes()
    89  		x := new(big.Int).SetBytes(reverseBytes(k.Data[:keySize]))
    90  		y := new(big.Int).SetBytes(reverseBytes(k.Data[keySize:]))
    91  		return sm2.PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
    92  	}
    93  
    94  	return nil, fmt.Errorf("unexpected TPM algorithm: %s", k.KeyAlg)
    95  }
    96  
    97  func reverseBytes(b []byte) []byte {
    98  	r := make([]byte, len(b))
    99  	for idx := range b {
   100  		r[idx] = b[len(b)-idx-1]
   101  	}
   102  	return r
   103  }
   104  
   105  // SetPubKey sets Data the value corresponding to passed `key`.
   106  func (k *Key) SetPubKey(key crypto.PublicKey) error {
   107  	k.Version = 0x10
   108  
   109  	switch key := key.(type) {
   110  	case *rsa.PublicKey:
   111  		k.KeyAlg = AlgRSA
   112  		n := key.N.Bytes()
   113  		k.KeySize.SetInBytes(uint16(len(n)))
   114  		k.Data = make([]byte, 4+len(n))
   115  		binaryOrder.PutUint32(k.Data, uint32(key.E))
   116  		copy(k.Data[4:], reverseBytes(n))
   117  		return nil
   118  
   119  	case *ecdsa.PublicKey:
   120  		var x, y *big.Int
   121  		k.KeyAlg = AlgECC
   122  		x, y = key.X, key.Y
   123  		if x == nil || y == nil {
   124  			return fmt.Errorf("the pubkey '%#+v' is invalid: x == nil || y == nil", key)
   125  		}
   126  		k.KeySize.SetInBits(256)
   127  		xB, yB := x.Bytes(), y.Bytes()
   128  		if len(xB) != int(k.KeySize.InBytes()) || len(yB) != int(k.KeySize.InBytes()) {
   129  			return fmt.Errorf("the pubkey '%#+v' is invalid: len(x)<%d> != %d || len(y)<%d> == %d",
   130  				key, len(xB), int(k.KeySize.InBytes()), len(yB), int(k.KeySize.InBytes()))
   131  		}
   132  		k.Data = make([]byte, 2*k.KeySize.InBytes())
   133  		copy(k.Data[:], reverseBytes(xB))
   134  		copy(k.Data[len(xB):], reverseBytes(yB))
   135  		return nil
   136  
   137  	case *sm2.PublicKey:
   138  		var x, y *big.Int
   139  		k.KeyAlg = AlgSM2
   140  		x, y = key.X, key.Y
   141  		if x == nil || y == nil {
   142  			return fmt.Errorf("the pubkey '%#+v' is invalid: x == nil || y == nil", key)
   143  		}
   144  		k.KeySize.SetInBits(256)
   145  		xB, yB := x.Bytes(), y.Bytes()
   146  		if len(xB) != int(k.KeySize.InBytes()) || len(yB) != int(k.KeySize.InBytes()) {
   147  			return fmt.Errorf("the pubkey '%#+v' is invalid: len(x)<%d> != %d || len(y)<%d> == %d",
   148  				key, len(xB), int(k.KeySize.InBytes()), len(yB), int(k.KeySize.InBytes()))
   149  		}
   150  		k.Data = make([]byte, 2*k.KeySize.InBytes())
   151  		copy(k.Data[:], reverseBytes(xB))
   152  		copy(k.Data[len(xB):], reverseBytes(yB))
   153  		return nil
   154  	}
   155  
   156  	return fmt.Errorf("unexpected key type: %T", key)
   157  }
   158  
   159  //PrintBPMPubKey prints the BPM public signing key hash to fuse into the Intel ME
   160  func (k *Key) PrintBPMPubKey(bpmAlg Algorithm) error {
   161  	buf := new(bytes.Buffer)
   162  	if len(k.Data) > 1 {
   163  		hash, err := bpmAlg.Hash()
   164  		if err != nil {
   165  			return err
   166  		}
   167  		if k.KeyAlg == AlgRSA {
   168  			if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil {
   169  				return err
   170  			}
   171  			if _, err := hash.Write(buf.Bytes()); err != nil {
   172  				return fmt.Errorf("unable to hash: %w", err)
   173  			}
   174  			fmt.Printf("   Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
   175  		} else if k.KeyAlg == AlgSM2 || k.KeyAlg == AlgECC {
   176  			if err := binary.Write(buf, binary.LittleEndian, k.Data); err != nil {
   177  				return err
   178  			}
   179  			if _, err := hash.Write(buf.Bytes()); err != nil {
   180  				return fmt.Errorf("unable to hash: %w", err)
   181  			}
   182  			fmt.Printf("   Boot Policy Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
   183  		} else {
   184  			fmt.Printf("   Boot Policy Manifest Pubkey Hash: Unknown Algorithm\n")
   185  		}
   186  	} else {
   187  		fmt.Printf("   Boot Policy Pubkey Hash: No km public key set in KM\n")
   188  	}
   189  
   190  	return nil
   191  }
   192  
   193  //PrintKMPubKey prints the KM public signing key hash to fuse into the Intel ME
   194  func (k *Key) PrintKMPubKey(kmAlg Algorithm) error {
   195  	buf := new(bytes.Buffer)
   196  	if len(k.Data) > 1 {
   197  		if k.KeyAlg == AlgRSA {
   198  			if err := binary.Write(buf, binary.LittleEndian, k.Data[4:]); err != nil {
   199  				return err
   200  			}
   201  			if err := binary.Write(buf, binary.LittleEndian, k.Data[:4]); err != nil {
   202  				return err
   203  			}
   204  			if kmAlg != AlgSHA256 && kmAlg != AlgSHA384 {
   205  				return fmt.Errorf("KM public key hash algorithm must be SHA256 or SHA384")
   206  			}
   207  			hash, err := kmAlg.Hash()
   208  			if err != nil {
   209  				return err
   210  			}
   211  			if _, err := hash.Write(buf.Bytes()); err != nil {
   212  				return fmt.Errorf("unable to hash: %w", err)
   213  			}
   214  			fmt.Printf("   Key Manifest Pubkey Hash: 0x%x\n", hash.Sum(nil))
   215  			// On SKL and KBL the exponent is not included in the KM hash
   216  			buf.Truncate(len(k.Data[4:]))
   217  			hash.Reset()
   218  			if _, err := hash.Write(buf.Bytes()); err != nil {
   219  				return fmt.Errorf("unable to hash: %w", err)
   220  			}
   221  			fmt.Printf("   Key Manifest Pubkey Hash (Skylake and Kabylake only): 0x%x\n", hash.Sum(nil))
   222  		} else {
   223  			fmt.Printf("   Key Manifest Pubkey Hash: Unsupported Algorithm\n")
   224  		}
   225  	} else {
   226  		fmt.Printf("   Key Manifest Pubkey Hash: No km public key set in KM\n")
   227  	}
   228  
   229  	return nil
   230  }