// 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 measure contains Go implementation of 'systemd-measure' command. // // This implements TPM PCR emulation, UKI signature measurement, signing the measured values. package measure import ( "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "os" "github.com/google/go-tpm/tpm2" "github.com/siderolabs/talos/internal/pkg/secureboot" "github.com/siderolabs/talos/internal/pkg/secureboot/measure/internal/pcr" tpm2internal "github.com/siderolabs/talos/internal/pkg/secureboot/tpm2" ) // SectionsData holds a map of Section to file path to the corresponding section. type SectionsData map[secureboot.Section]string func loadRSAKey(path string) (*rsa.PrivateKey, error) { keyData, err := os.ReadFile(path) if err != nil { return nil, err } // convert private key to rsa.PrivateKey rsaPrivateKeyBlock, _ := pem.Decode(keyData) if rsaPrivateKeyBlock == nil { return nil, err } rsaKey, err := x509.ParsePKCS1PrivateKey(rsaPrivateKeyBlock.Bytes) if err != nil { return nil, fmt.Errorf("parse private key failed: %v", err) } return rsaKey, nil } // GenerateSignedPCR generates the PCR signed data for a given set of UKI file sections. func GenerateSignedPCR(sectionsData SectionsData, rsaKeyPath string) (*tpm2internal.PCRData, error) { rsaKey, err := loadRSAKey(rsaKeyPath) if err != nil { return nil, err } data := &tpm2internal.PCRData{} for _, algo := range []struct { alg tpm2.TPMAlgID bankDataSetter *[]tpm2internal.BankData }{ { alg: tpm2.TPMAlgSHA1, bankDataSetter: &data.SHA1, }, { alg: tpm2.TPMAlgSHA256, bankDataSetter: &data.SHA256, }, { alg: tpm2.TPMAlgSHA384, bankDataSetter: &data.SHA384, }, { alg: tpm2.TPMAlgSHA512, bankDataSetter: &data.SHA512, }, } { bankData, err := pcr.CalculateBankData(secureboot.UKIPCR, algo.alg, sectionsData, rsaKey) if err != nil { return nil, err } *algo.bankDataSetter = bankData } return data, nil }