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 }