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 }