github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/keys.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 // Key parsing logic is based on AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h and Family 19h Processors 8 // Publication # 55758 9 // Issue Date: August 2020 10 // Revision: 1.11 11 12 import ( 13 "bytes" 14 "crypto/rsa" 15 "encoding/binary" 16 "errors" 17 "fmt" 18 "math/big" 19 20 "strings" 21 22 amd_manifest "github.com/linuxboot/fiano/pkg/amd/manifest" 23 ) 24 25 // KeyID is the primary identifier of a key 26 type KeyID Buf16B 27 28 // Hex returns a hexadecimal string representation of a KeyID 29 func (kid *KeyID) Hex() string { 30 var s strings.Builder 31 fmt.Fprintf(&s, "%x", *kid) 32 return s.String() 33 } 34 35 // String returns the hexadecimal string representation of a KeyID 36 func (kid *KeyID) String() string { 37 return kid.Hex() 38 } 39 40 // KeyIDs represents a list of KeyID 41 type KeyIDs []KeyID 42 43 // String returns a string representation of all KeyIDs 44 func (kids KeyIDs) String() string { 45 if len(kids) == 0 { 46 return "" 47 } 48 49 var s strings.Builder 50 fmt.Fprintf(&s, "%s", kids[0].Hex()) 51 for _, kid := range kids[1:] { 52 fmt.Fprintf(&s, ", %s", kid.Hex()) 53 } 54 return s.String() 55 } 56 57 // KeyUsageFlag describes a known values for KeyUsageFlag field of AMD PSP Key structure 58 type KeyUsageFlag uint32 59 60 const ( 61 // SignAMDBootloaderPSPSMU tells that the corresponding key is authorized to sign AMD developed PSP Boot 62 // Loader and AMD developed PSP FW components and SMU FW. 63 // See Table 26. RSA Key Format Fields of AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h and 19h Processors 64 // Revision 1.11 65 SignAMDBootloaderPSPSMU KeyUsageFlag = 0 66 67 // SignBIOS tells that the corresponding key is authorized to sign BIOS 68 SignBIOS KeyUsageFlag = 1 69 70 // SignAMDOEMPSP tells that the corresponding key is authorized to sign PSP FW (both AMD developed and OEM developed) 71 SignAMDOEMPSP KeyUsageFlag = 2 72 73 // PSBSignBIOS tells that a key is authorized to sign BIOS for platform secure boot. 74 // See Table 8. RSA Key Format Fields of Enabling Platform Secure Boot 75 // for AMD Family 17h Models 00h–0Fh and 30h–3Fh and Family 19h Models 00h–0Fh Processor-Based Server Platforms 76 // Revision 0.91 77 PSBSignBIOS KeyUsageFlag = 8 78 ) 79 80 // KeyData represents the binary format (as it is stored in an image) of the information associated with a key 81 type KeyData struct { 82 VersionID uint32 83 KeyID KeyID 84 CertifyingKeyID Buf16B 85 KeyUsageFlag KeyUsageFlag 86 Reserved Buf16B 87 ExponentSize uint32 88 ModulusSize uint32 89 Exponent []byte 90 Modulus []byte 91 } 92 93 // Key structure extracted from the firmware 94 type Key struct { 95 data KeyData 96 } 97 98 // PlatformBindingInfo describes information of BIOS Signing Key to Platform Binding information 99 type PlatformBindingInfo struct { 100 VendorID uint8 101 KeyRevisionID uint8 102 PlatformModelID uint8 103 } 104 105 func (b PlatformBindingInfo) String() string { 106 var s strings.Builder 107 fmt.Fprintf(&s, "Vendor ID: %X\n", b.VendorID) 108 fmt.Fprintf(&s, "Key Revision ID: %X\n", b.KeyRevisionID) 109 fmt.Fprintf(&s, "Platform Model ID: %X\n", b.PlatformModelID) 110 return s.String() 111 } 112 113 // GetPlatformBindingInfo for PSBSignBIOS key returns BIOS Signing Key to Platform Binding information 114 func GetPlatformBindingInfo(k *Key) (PlatformBindingInfo, error) { 115 if k.data.KeyUsageFlag != PSBSignBIOS { 116 return PlatformBindingInfo{}, fmt.Errorf("not a PSBSignBios key usage flag: %v", k.data.KeyUsageFlag) 117 } 118 return parsePlatformBinding(k.data.Reserved), nil 119 } 120 121 func parsePlatformBinding(reserved Buf16B) PlatformBindingInfo { 122 return PlatformBindingInfo{ 123 VendorID: reserved[0], 124 KeyRevisionID: reserved[1] & 7, // Bits 0:3 => Key Revision ID 125 PlatformModelID: reserved[1] << 3, // Bits 4:7 => Platform Model ID 126 } 127 } 128 129 // SecurityFeatureVector represents a security feature selection vector of BIOS OEM key 130 type SecurityFeatureVector struct { 131 DisableBIOSKeyAntiRollback bool 132 DisableAMDBIOSKeyUse bool 133 DisableSecureDebugUnlock bool 134 } 135 136 func (sfv SecurityFeatureVector) String() string { 137 var s strings.Builder 138 fmt.Fprintf(&s, "DISABLE_BIOS_KEY_ANTI_ROLLBACK: %t\n", sfv.DisableBIOSKeyAntiRollback) 139 fmt.Fprintf(&s, "DISABLE_AMD_BIOS_KEY_USE: %t\n", sfv.DisableAMDBIOSKeyUse) 140 fmt.Fprintf(&s, "DISABLE_SECURE_DEBUG_UNLOCK: %t\n", sfv.DisableSecureDebugUnlock) 141 return s.String() 142 } 143 144 // GetSecurityFeatureVector for PSBSignBIOS key returns a security feature selection vector 145 func GetSecurityFeatureVector(k *Key) (SecurityFeatureVector, error) { 146 if k.data.KeyUsageFlag != PSBSignBIOS { 147 return SecurityFeatureVector{}, fmt.Errorf("not a PSBSignBios key usage flag: %v", k.data.KeyUsageFlag) 148 } 149 return parseSecurityFeatureVector(k.data.Reserved), nil 150 } 151 152 func parseSecurityFeatureVector(reserved Buf16B) SecurityFeatureVector { 153 return SecurityFeatureVector{ 154 DisableBIOSKeyAntiRollback: reserved[3]&1 == 1, 155 DisableAMDBIOSKeyUse: (reserved[3]<<1)&1 == 1, 156 DisableSecureDebugUnlock: (reserved[3]<<2)&1 == 1, 157 } 158 } 159 160 // Key creation functions manage two slightly different key structures available in firmware: 161 // 162 // 1) Those serialized into key tokens 163 // 2) Those serialized into the key database 164 // 165 // Format 2) is as follow: 166 // 167 // type key struct { 168 // dataSize uint32 169 // version uint32 170 // keyUsageFlag uint32 171 // publicExponent [4]uint8 172 // keyID [16]uint8 173 // keySize uint32 174 // reserved Buf44B 175 // modulus []byte 176 // } 177 // 178 // From a bytes buffer, there is no way to distinguish between the two cases above, so an indication 179 // of which format to use should come from the caller (by calling NewKey<TYPE>). 180 // 181 // Both formats will be deserialized into Key structure. Some fields of Key might contain zero value 182 // (e.g. certifying key ID for keys extracted from the key database, which is indirectly the AMD root 183 // key as it signs the whole key database). 184 // 185 // If the key is a token key, the signature is validated. 186 // Additional safety checks are implemented during serialization: 187 // if a `certifyingKeyID` is retrieved from the buffer and it's not null, a KeySet must be available for validation, 188 // or an error will be returned. Callers however are ultimately responsible to make sure that a KeySet is passed if 189 // a key should be validated. 190 191 func zeroCertifyingKeyID(key *Key) bool { 192 for _, v := range key.data.CertifyingKeyID { 193 if v != 0 { 194 return false 195 } 196 } 197 return true 198 } 199 200 // readExponent reads exponent value from a buffer, assuming exponent size 201 // has already been populated. 202 func readExponent(buff *bytes.Buffer, key *Key) error { 203 if key.data.ExponentSize%8 != 0 { 204 return newErrInvalidFormat(fmt.Errorf("exponent size is not divisible by 8")) 205 } 206 exponent := make([]byte, key.data.ExponentSize/8) 207 if err := binary.Read(buff, binary.LittleEndian, &exponent); err != nil { 208 return newErrInvalidFormat(fmt.Errorf("could not parse exponent: %w", err)) 209 } 210 key.data.Exponent = exponent 211 return nil 212 } 213 214 // readModulus reads modulus value from a buffer, assuming modulus size 215 // has already been populated 216 func readModulus(buff *bytes.Buffer, key *Key) error { 217 if key.data.ModulusSize%8 != 0 { 218 return newErrInvalidFormat(fmt.Errorf("modulus size is not divisible by 8")) 219 } 220 221 modulus := make([]byte, key.data.ModulusSize/8) 222 if err := binary.Read(buff, binary.LittleEndian, &modulus); err != nil { 223 return newErrInvalidFormat(fmt.Errorf("could not parse modulus: %w", err)) 224 } 225 key.data.Modulus = modulus 226 return nil 227 } 228 229 // newTokenOrRootKey creates the common parts of Token and Root keys 230 func newTokenOrRootKey(buff *bytes.Buffer) (*Key, error) { 231 232 key := Key{} 233 234 if err := binary.Read(buff, binary.LittleEndian, &key.data.VersionID); err != nil { 235 return nil, newErrInvalidFormat(fmt.Errorf("could not parse VersionID: %w", err)) 236 } 237 if err := binary.Read(buff, binary.LittleEndian, &key.data.KeyID); err != nil { 238 return nil, newErrInvalidFormat(fmt.Errorf("could not parse KeyID: %w", err)) 239 } 240 if err := binary.Read(buff, binary.LittleEndian, &key.data.CertifyingKeyID); err != nil { 241 return nil, newErrInvalidFormat(fmt.Errorf("could not parse Certifying KeyID: %w", err)) 242 } 243 if err := binary.Read(buff, binary.LittleEndian, &key.data.KeyUsageFlag); err != nil { 244 return nil, newErrInvalidFormat(fmt.Errorf("could not parse Key Usage Flag: %w", err)) 245 } 246 if err := binary.Read(buff, binary.LittleEndian, &key.data.Reserved); err != nil { 247 return nil, newErrInvalidFormat(fmt.Errorf("could not parse reserved area: %w", err)) 248 } 249 if err := binary.Read(buff, binary.LittleEndian, &key.data.ExponentSize); err != nil { 250 return nil, newErrInvalidFormat(fmt.Errorf("could not parse exponent size: %w", err)) 251 } 252 if err := binary.Read(buff, binary.LittleEndian, &key.data.ModulusSize); err != nil { 253 return nil, newErrInvalidFormat(fmt.Errorf("could not parse modulus size: %w", err)) 254 } 255 256 if err := readExponent(buff, &key); err != nil { 257 return nil, err 258 } 259 260 if err := readModulus(buff, &key); err != nil { 261 return nil, err 262 } 263 return &key, nil 264 } 265 266 // NewRootKey creates a new root key object which is considered trusted without any need for signature check 267 func NewRootKey(buff *bytes.Buffer) (*Key, error) { 268 key, err := newTokenOrRootKey(buff) 269 if err != nil { 270 return nil, fmt.Errorf("cannot parse root key: %w", err) 271 } 272 273 if key.data.KeyID != key.data.CertifyingKeyID { 274 return nil, newErrInvalidFormat(fmt.Errorf("root key must have certifying key ID == key ID (key ID: %x, certifying key ID: %x)", key.data.KeyID, key.data.CertifyingKeyID)) 275 } 276 return key, err 277 278 } 279 280 // NewTokenKey create a new key object from a signed token 281 func NewTokenKey(buff *bytes.Buffer, keySet KeySet) (*Key, error) { 282 283 raw := buff.Bytes() 284 285 key, err := newTokenOrRootKey(buff) 286 if err != nil { 287 return nil, fmt.Errorf("could not create new token key: %w", err) 288 } 289 290 signingKeyID := KeyID(key.data.CertifyingKeyID) 291 signingKey := keySet.GetKey(signingKeyID) 292 if signingKey == nil { 293 return nil, fmt.Errorf("could not find signing key with ID %s for key token key", signingKeyID.Hex()) 294 } 295 296 signatureSize, err := signingKey.SignatureSize() 297 if err != nil { 298 return nil, &SignatureCheckError{signingKey: signingKey, err: fmt.Errorf("could not get signature length of a key: %w", err)} 299 } 300 301 // validate the signature of the new token key 302 signature := make([]byte, signatureSize) 303 if err := binary.Read(buff, binary.LittleEndian, &signature); err != nil { 304 return nil, newErrInvalidFormat(fmt.Errorf("could not parse signature from key token: %w", err)) 305 } 306 307 // A key extracted from a signed token has the following structure: 308 // * 64 bytes header 309 // * exponent 310 // * modulus 311 // * signature. 312 // 313 // Exponent, modulus and signature are all of the same size. Only the latter is not signed, hence the length 314 // of the signed payload is header size + 2 * exponent/modulus size. 315 lenSigned := uint64(64 + 2*key.data.ModulusSize/8) 316 if uint64(len(raw)) < lenSigned { 317 return nil, newErrInvalidFormat(fmt.Errorf("length of signed token is not sufficient: expected > %d, got %d", lenSigned, len(raw))) 318 } 319 320 // Validate the signature of the raw token 321 if _, err := NewSignedBlob(reverse(signature), raw[:lenSigned], signingKey); err != nil { 322 return nil, fmt.Errorf("could not validate the signature of token key: %w", err) 323 } 324 return key, nil 325 } 326 327 // NewKeyFromDatabase creates a new key object from key database entry 328 func NewKeyFromDatabase(buff *bytes.Buffer) (*Key, error) { 329 key := Key{} 330 331 var ( 332 dataSize uint32 333 numRead uint64 334 ) 335 336 if err := readAndCountSize(buff, binary.LittleEndian, &dataSize, &numRead); err != nil { 337 return nil, newErrInvalidFormat(fmt.Errorf("could not parse dataSize: %w", err)) 338 } 339 340 // consider if we still have enough data to parse a whole key entry which is dataSize long. 341 // dataSize includes the uint32 dataSize field itself 342 if uint64(dataSize) > uint64(buff.Len())+4 { 343 return nil, newErrInvalidFormat(fmt.Errorf("buffer is not long enough (%d) to satisfy dataSize (%d)", buff.Len(), dataSize)) 344 } 345 346 if err := readAndCountSize(buff, binary.LittleEndian, &key.data.VersionID, &numRead); err != nil { 347 return nil, newErrInvalidFormat(fmt.Errorf("could not parse VersionID: %w", err)) 348 } 349 350 if err := readAndCountSize(buff, binary.LittleEndian, &key.data.KeyUsageFlag, &numRead); err != nil { 351 return nil, newErrInvalidFormat(fmt.Errorf("could not parse key usage flags: %w", err)) 352 } 353 354 var publicExponent Buf4B 355 if err := readAndCountSize(buff, binary.LittleEndian, &publicExponent, &numRead); err != nil { 356 return nil, newErrInvalidFormat(fmt.Errorf("could not parse public exponent: %w", err)) 357 } 358 key.data.Exponent = publicExponent[:] 359 360 if err := readAndCountSize(buff, binary.LittleEndian, &key.data.KeyID, &numRead); err != nil { 361 return nil, newErrInvalidFormat(fmt.Errorf("could not parse key id: %w", err)) 362 } 363 364 var keySize uint32 365 if err := readAndCountSize(buff, binary.LittleEndian, &keySize, &numRead); err != nil { 366 return nil, newErrInvalidFormat(fmt.Errorf("could not parse key size: %w", err)) 367 } 368 if keySize == 0 { 369 return nil, newErrInvalidFormat(fmt.Errorf("key size cannot be 0")) 370 } 371 372 if keySize%8 != 0 { 373 return nil, newErrInvalidFormat(fmt.Errorf("key size is not divisible by 8 (%d)", keySize)) 374 } 375 376 key.data.ExponentSize = keySize 377 key.data.ModulusSize = keySize 378 379 var reserved Buf44B 380 if err := readAndCountSize(buff, binary.LittleEndian, &reserved, &numRead); err != nil { 381 return nil, newErrInvalidFormat(fmt.Errorf("could not parse reserved area: %w", err)) 382 } 383 // check if we have enough data left, based on keySize and dataSize 384 if (numRead + uint64(keySize)/8) > uint64(dataSize) { 385 return nil, newErrInvalidFormat(fmt.Errorf("inconsistent header, read so far %d, total size is %d, key size to read is %d, which goes out of bound", numRead, dataSize, keySize)) 386 } 387 388 if err := readModulus(buff, &key); err != nil { 389 return nil, err 390 } 391 392 if !zeroCertifyingKeyID(&key) { 393 return nil, newErrInvalidFormat(fmt.Errorf("key extracted from key database should have zero certifying key ID")) 394 } 395 396 return &key, nil 397 } 398 399 // String returns a string representation of the key 400 func (k *Key) String() string { 401 var s strings.Builder 402 403 pubKey, err := k.Get() 404 if err != nil { 405 fmt.Fprintf(&s, "could not get RSA key from raw bytes: %v\n", err) 406 return s.String() 407 } 408 409 fmt.Fprintf(&s, "Version ID: 0x%x\n", k.data.VersionID) 410 fmt.Fprintf(&s, "Key ID: 0x%s\n", k.data.KeyID.Hex()) 411 fmt.Fprintf(&s, "Certifying Key ID: 0x%x\n", k.data.CertifyingKeyID) 412 fmt.Fprintf(&s, "Key Usage Flag: 0x%x\n", k.data.KeyUsageFlag) 413 if k.data.KeyUsageFlag == PSBSignBIOS { 414 fmt.Fprintf(&s, "%s", parsePlatformBinding(k.data.Reserved)) 415 fmt.Fprintf(&s, "%s", parseSecurityFeatureVector(k.data.Reserved)) 416 } 417 fmt.Fprintf(&s, "Exponent size: 0x%x (dec %d) \n", k.data.ExponentSize, k.data.ExponentSize) 418 fmt.Fprintf(&s, "Modulus size: 0x%x (dec %d)\n", k.data.ModulusSize, k.data.ModulusSize) 419 420 switch rsaKey := pubKey.(type) { 421 case *rsa.PublicKey: 422 fmt.Fprintf(&s, "Exponent: 0x%d\n", rsaKey.E) 423 default: 424 fmt.Fprintf(&s, "Exponent: key is not RSA, cannot get decimal exponent\n") 425 } 426 427 fmt.Fprintf(&s, "Modulus: 0x%x\n", k.data.Modulus) 428 return s.String() 429 } 430 431 // Get returns the PublicKey object from golang standard library. 432 // AMD Milan supports only RSA Keys (2048, 4096), future platforms 433 // might add support for additional key types. 434 func (k *Key) Get() (interface{}, error) { 435 if err := k.checkValid(); err != nil { 436 return nil, err 437 } 438 439 N := big.NewInt(0) 440 E := big.NewInt(0) 441 442 // modulus and exponent are read as little endian 443 rsaPk := rsa.PublicKey{N: N.SetBytes(reverse(k.data.Modulus)), E: int(E.SetBytes(reverse(k.data.Exponent)).Int64())} 444 return &rsaPk, nil 445 } 446 447 // SignatureSize returns the size of the signature 448 func (k *Key) SignatureSize() (int, error) { 449 if err := k.checkValid(); err != nil { 450 return 0, err 451 } 452 return len(k.data.Modulus), nil 453 } 454 455 func (k *Key) checkValid() error { 456 if len(k.data.Exponent) == 0 { 457 return fmt.Errorf("invalid key: exponent size is 0") 458 } 459 if len(k.data.Modulus) == 0 { 460 return fmt.Errorf("invalid key: modulus size is 0") 461 } 462 return nil 463 } 464 465 // GetKeys returns all the keys known to the system in the form of a KeySet. 466 // The firmware itself contains a key database, but that is not comprehensive 467 // of all the keys known to the system (e.g. additional keys might be OEM key, 468 // ABL signing key, etc.). 469 func GetKeys(amdFw *amd_manifest.AMDFirmware, level uint) (KeySet, error) { 470 keySet := NewKeySet() 471 err := getKeysFromDatabase(amdFw, level, keySet) 472 if err != nil { 473 return keySet, fmt.Errorf("could not get key from table into KeySet: %w", err) 474 } 475 476 // Extract ABL signing key (entry 0x0A in PSP Directory), which is signed with AMD Public Key. 477 pubKeyBytes, err := ExtractPSPEntry(amdFw, level, ABLPublicKey) 478 if err != nil { 479 return keySet, fmt.Errorf("could not extract raw PSP entry for ABL Public Key: %w", err) 480 } 481 ablPk, err := NewTokenKey(bytes.NewBuffer(pubKeyBytes), keySet) 482 if err != nil { 483 return keySet, addFirmwareItemToError(err, newPSPDirectoryEntryItem(uint8(level), ABLPublicKey)) 484 } 485 486 err = keySet.AddKey(ablPk, ABLKey) 487 if err != nil { 488 return keySet, fmt.Errorf("could not add ABL signing key to key set: %w", err) 489 } 490 491 // Extract OEM signing key (entry 0x05 in BIOS Directory table) 492 // in PSB disabled this entry doesn't exist 493 pubKeyBytes, err = ExtractBIOSEntry(amdFw, level, OEMSigningKeyEntry, 0) 494 if err != nil { 495 if !errors.As(err, &ErrNotFound{}) { 496 return keySet, fmt.Errorf("could not extract raw BIOS directory entry for OEM Public Key: %w", err) 497 } 498 } else { 499 oemPk, err := NewTokenKey(bytes.NewBuffer(pubKeyBytes), keySet) 500 if err != nil { 501 return keySet, fmt.Errorf("could not extract OEM public key: %w", err) 502 } 503 504 err = keySet.AddKey(oemPk, OEMKey) 505 if err != nil { 506 return keySet, fmt.Errorf("could not add OEM signing key to key set: %w", err) 507 } 508 } 509 return keySet, nil 510 }