Andrey Smirnov 3c9f7a7de6
chore: re-enable nolintlint and typecheck linters
Drop startup/rand.go, as since Go 1.20 `rand.Seed` is done
automatically.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2023-08-25 01:05:41 +04:00

140 lines
3.4 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package tpm2 provides TPM2.0 related functionality helpers.
package tpm2
import (
"fmt"
"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpm2/transport"
"github.com/siderolabs/talos/internal/pkg/secureboot"
"github.com/siderolabs/talos/pkg/machinery/constants"
)
// Seal seals the key using TPM2.0.
func Seal(key []byte) (*SealedResponse, error) {
t, err := transport.OpenTPM()
if err != nil {
return nil, err
}
defer t.Close() //nolint:errcheck
// fail early if PCR banks are not present or filled with all zeroes or 0xff
if err = validatePCRBanks(t); err != nil {
return nil, err
}
sealingPolicyDigest, err := calculateSealingPolicyDigest(t)
if err != nil {
return nil, err
}
primary := tpm2.CreatePrimary{
PrimaryHandle: tpm2.TPMRHOwner,
InPublic: tpm2.New2B(tpm2.ECCSRKTemplate),
}
createPrimaryResponse, err := primary.Execute(t)
if err != nil {
return nil, err
}
defer func() {
flush := tpm2.FlushContext{
FlushHandle: createPrimaryResponse.ObjectHandle,
}
_, flushErr := flush.Execute(t)
if flushErr != nil {
err = flushErr
}
}()
outPub, err := createPrimaryResponse.OutPublic.Contents()
if err != nil {
return nil, err
}
create := tpm2.Create{
ParentHandle: tpm2.AuthHandle{
Handle: createPrimaryResponse.ObjectHandle,
Name: createPrimaryResponse.Name,
Auth: tpm2.HMAC(
tpm2.TPMAlgSHA256,
20,
tpm2.Salted(createPrimaryResponse.ObjectHandle, *outPub),
tpm2.AESEncryption(128, tpm2.EncryptInOut),
),
},
InSensitive: tpm2.TPM2BSensitiveCreate{
Sensitive: &tpm2.TPMSSensitiveCreate{
Data: tpm2.NewTPMUSensitiveCreate(&tpm2.TPM2BSensitiveData{
Buffer: key,
}),
},
},
InPublic: tpm2.New2B(tpm2.TPMTPublic{
Type: tpm2.TPMAlgKeyedHash,
NameAlg: tpm2.TPMAlgSHA256,
ObjectAttributes: tpm2.TPMAObject{
FixedTPM: true,
FixedParent: true,
},
Parameters: tpm2.NewTPMUPublicParms(tpm2.TPMAlgKeyedHash, &tpm2.TPMSKeyedHashParms{
Scheme: tpm2.TPMTKeyedHashScheme{
Scheme: tpm2.TPMAlgNull,
},
}),
AuthPolicy: tpm2.TPM2BDigest{
Buffer: sealingPolicyDigest,
},
}),
}
createResp, err := create.Execute(t)
if err != nil {
return nil, err
}
resp := SealedResponse{
SealedBlobPrivate: tpm2.Marshal(createResp.OutPrivate),
SealedBlobPublic: tpm2.Marshal(createResp.OutPublic),
KeyName: tpm2.Marshal(createPrimaryResponse.Name),
PolicyDigest: sealingPolicyDigest,
}
return &resp, nil
}
func calculateSealingPolicyDigest(t transport.TPM) ([]byte, error) {
pcrSelector, err := CreateSelector([]int{secureboot.SecureBootStatePCR})
if err != nil {
return nil, fmt.Errorf("failed to create PCR selection: %v", err)
}
pcrSelection := tpm2.TPMLPCRSelection{
PCRSelections: []tpm2.TPMSPCRSelection{
{
Hash: tpm2.TPMAlgSHA256,
PCRSelect: pcrSelector,
},
},
}
pcrValue, err := ReadPCR(t, secureboot.SecureBootStatePCR)
if err != nil {
return nil, err
}
sealingDigest, err := CalculateSealingPolicyDigest(pcrValue, pcrSelection, constants.PCRPublicKey)
if err != nil {
return nil, fmt.Errorf("failed to calculate sealing policy digest: %v", err)
}
return sealingDigest, nil
}