github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/keyset.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 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 "strings" 13 14 amd_manifest "github.com/linuxboot/fiano/pkg/amd/manifest" 15 ) 16 17 // KeyType represents the type of the key stored in KeySet 18 type KeyType string 19 20 const ( 21 // OEMKey represents the OEM signing key 22 OEMKey KeyType = "OEMKey" 23 // AMDRootKey represents the AMD signing key 24 AMDRootKey KeyType = "AMDRootKey" 25 // KeyDatabaseKey represents a key extracted from KeyDatabase 26 KeyDatabaseKey KeyType = "KeyDatabaseKey" 27 // ABLKey represents the ABL signing key 28 ABLKey KeyType = "ALBKey" 29 ) 30 31 // KeySet is a container for all keys known to the system 32 type KeySet struct { 33 // db holds a mapping between keyID and key 34 db map[KeyID]*Key 35 // keyType holds a mapping betweek KeyType and KeyID 36 keyType map[KeyType][]KeyID 37 } 38 39 // String returns a string representation of the key in the set 40 func (kdb *KeySet) String() string { 41 var s strings.Builder 42 fmt.Fprintf(&s, "Number of keys in key set: %d\n\n", len(kdb.db)) 43 44 for _, key := range kdb.db { 45 fmt.Fprintf(&s, "%s\n\n", key.String()) 46 } 47 return s.String() 48 } 49 50 // AddKey adds a key to the key set 51 func (kdb KeySet) AddKey(k *Key, keyType KeyType) error { 52 if _, ok := kdb.db[k.data.KeyID]; ok { 53 return fmt.Errorf("cannot add key id %s to set, key with same id already exists", k.data.KeyID.Hex()) 54 } 55 56 kdb.db[k.data.KeyID] = k 57 // assume the key cannot be already present in the keyType mapping 58 kdb.keyType[keyType] = append(kdb.keyType[keyType], k.data.KeyID) 59 return nil 60 } 61 62 // NewKeySet builds an empty key set object 63 func NewKeySet() KeySet { 64 keySet := KeySet{} 65 keySet.db = make(map[KeyID]*Key) 66 keySet.keyType = make(map[KeyType][]KeyID) 67 return keySet 68 } 69 70 // GetKey returns a key if known to the KeySet. If the key is not known, null is returned 71 func (kdb KeySet) GetKey(id KeyID) *Key { 72 if kdb.db == nil { 73 return nil 74 } 75 return kdb.db[id] 76 } 77 78 // AllKeyIDs returns a list of all KeyIDs stored in the KeySet 79 func (kdb KeySet) AllKeyIDs() KeyIDs { 80 keyIDs := make(KeyIDs, 0, len(kdb.db)) 81 for keyID := range kdb.db { 82 keyIDs = append(keyIDs, keyID) 83 } 84 return keyIDs 85 } 86 87 // KeysetFromType returns a KeySet containing all KeyIDs of a specific type 88 func (kdb KeySet) KeysetFromType(keyType KeyType) (KeySet, error) { 89 if _, ok := kdb.keyType[keyType]; !ok { 90 return NewKeySet(), newErrNotFound(nil) 91 } 92 keySet := NewKeySet() 93 for _, keyID := range kdb.keyType[keyType] { 94 key := kdb.GetKey(keyID) 95 if key == nil { 96 return NewKeySet(), newErrInvalidFormat(fmt.Errorf("KeySet in inconsistent state, no key is present with keyID %s", keyID.Hex())) 97 } 98 99 err := keySet.AddKey(key, keyType) 100 if err != nil { 101 return NewKeySet(), fmt.Errorf("unable to add key %s: %w", keyID, err) 102 } 103 } 104 return keySet, nil 105 } 106 107 // keyDBHeader represents the header pre-pended to keydb structure 108 type keyDBHeader struct { 109 DataSize uint32 110 Version uint32 111 Cookie uint32 112 Reserved Buf36B 113 CustomerDefined Buf32B 114 } 115 116 func readAndCountSize(r io.Reader, order binary.ByteOrder, data interface{}, counter *uint64) error { 117 if err := binary.Read(r, order, data); err != nil { 118 return err 119 } 120 if counter != nil { 121 *counter += uint64(binary.Size(data)) 122 } 123 return nil 124 } 125 126 // extractKeydbHeader parses keydbHeader from binary buffer. KeyDB header is supposed to be 80 bytes long 127 func extractKeydbHeader(buff io.Reader) (*keyDBHeader, error) { 128 header := keyDBHeader{} 129 130 if err := binary.Read(buff, binary.LittleEndian, &header); err != nil { 131 return nil, fmt.Errorf("could not read key database header: %w", err) 132 } 133 134 return &header, nil 135 } 136 137 // parseKeyDatabase parses a raw buffer representing a key database and adds all extracted key 138 // to the associated keySet. The raw buffer must be stripped off of the PSP header and the signature 139 // appended at the end. 140 func parseKeyDatabase(rawDB []byte, keySet KeySet) error { 141 142 buff := bytes.NewBuffer(rawDB) 143 _, err := extractKeydbHeader(buff) 144 if err != nil { 145 return fmt.Errorf("could not extract keydb header: %w", err) 146 } 147 148 for { 149 if buff.Len() == 0 { 150 break 151 } 152 key, err := NewKeyFromDatabase(buff) 153 if err != nil { 154 return fmt.Errorf("could not extract key entry from key database: %w", err) 155 } 156 if err := keySet.AddKey(key, KeyDatabaseKey); err != nil { 157 return fmt.Errorf("cannot add key to key database: %w", err) 158 } 159 } 160 161 return nil 162 } 163 164 // getKeysFromDatabase extracts the keys in the firmware key database and adds them to the KeySet passed 165 // as argument after validating the signature of the database itself 166 func getKeysFromDatabase(amdFw *amd_manifest.AMDFirmware, pspLevel uint, keySet KeySet) error { 167 168 /** 169 * PSP Directory Level 2 does not contain the AMD 170 * Public Root Keys, so we are forced to use PSP Directory 171 * Level 1 to get them, and not have it configurable 172 */ 173 pubKeyBytes, err := ExtractPSPEntry(amdFw, 1, AMDPublicKeyEntry) 174 if err != nil { 175 return fmt.Errorf("could not extract raw PSP entry for AMD Public Key: %w", err) 176 } 177 amdPk, err := NewRootKey(bytes.NewBuffer(pubKeyBytes)) 178 if err != nil { 179 return addFirmwareItemToError(err, newPSPDirectoryEntryItem(uint8(pspLevel), AMDPublicKeyEntry)) 180 } 181 182 // All keys which get added the KeySet are supposed to be trusted. AMD root key is trusted as a result of being matched against a 183 // "source of truth" (in hardware, this is a hash burnt into the CPU. Software tooling should check it against some external 184 // reference). 185 if err := keySet.AddKey(amdPk, AMDRootKey); err != nil { 186 return fmt.Errorf("could not add AMD key to the key database: %w", err) 187 } 188 189 data, err := ExtractPSPEntry(amdFw, pspLevel, KeyDatabaseEntry) 190 if err != nil { 191 return fmt.Errorf("could not extract entry 0x%x (KeyDatabaseEntry) from PSP table: %w", KeyDatabaseEntry, err) 192 } 193 194 binary, err := newPSPBinary(data) 195 if err != nil { 196 return newErrInvalidFormatWithItem(newPSPDirectoryEntryItem(uint8(pspLevel), KeyDatabaseEntry), 197 fmt.Errorf("could not create PSB binary from raw data for entry 0x%x (KeyDatabaseEntry): %w", KeyDatabaseEntry, err)) 198 } 199 200 // getSignedBlob returns the whole PSP blob as a signature-validated structure. 201 signedBlob, err := binary.getSignedBlob(keySet) 202 if err != nil { 203 return addFirmwareItemToError(err, newPSPDirectoryEntryItem(uint8(pspLevel), KeyDatabaseEntry)) 204 } 205 206 // We need to strip off pspHeader to get the content which actually represents the keys database 207 signedData := signedBlob.SignedData() 208 if len(signedData) <= pspHeaderSize { 209 return newErrInvalidFormatWithItem(newPSPDirectoryEntryItem(uint8(pspLevel), KeyDatabaseEntry), 210 fmt.Errorf("length of key database entry (%d) is less than pspHeader length (%d)", len(signedData), pspHeaderSize)) 211 } 212 213 return parseKeyDatabase(signedData[pspHeaderSize:], keySet) 214 }