diff --git a/pkg/pillar/cmd/msrv/activatecred.go b/pkg/pillar/cmd/msrv/activatecred.go new file mode 100644 index 00000000000..e5f7e49c1f6 --- /dev/null +++ b/pkg/pillar/cmd/msrv/activatecred.go @@ -0,0 +1,134 @@ +package msrv + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/tpmutil" + etpm "github.com/lf-edge/eve/pkg/pillar/evetpm" +) + +// ActivateCredTpmParam provides the parameters required to activate the +// credential using HWTPM EK and HWTPM AIK. +type ActivateCredTpmParam struct { + Ek string `json:"ek"` // HWTPM EK public key + AikPub string `json:"aikpub"` // HWTPM AIK public key + AikName string `json:"aikname"` // HWTPM AIK name +} + +// ActivateCredGenerated contains the generated credential and data to sign. +type ActivateCredGenerated struct { + Data string `json:"data"` + Cred string `json:"cred"` + Secret string `json:"secret"` +} + +// ActivateCredActivated contains the activated credential (decrypted secret) +// and signature of the ActivateCredGenerated.Data. +type ActivateCredActivated struct { + Secret string `json:"secret"` + Sig string `json:"sig"` +} + +// handles the GET request /tmp/activate-credential/, this is used to get the +// HTPM EK public key, HWTPM AIK public key, HWTPM AIK name. +func getActivateCredntialParams() ([]byte, []byte, []byte, error) { + rw, err := tpm2.OpenTPM(etpm.TpmDevicePath) + if err != nil { + return nil, nil, nil, err + } + defer rw.Close() + + ekPub, _, _, err := tpm2.ReadPublic(rw, etpm.TpmEKHdl) + if err != nil { + return nil, nil, nil, err + } + + ekPubByte, err := ekPub.Encode() + if err != nil { + return nil, nil, nil, err + } + + var aikName tpmutil.U16Bytes + aikPub, aikName, _, err := tpm2.ReadPublic(rw, etpm.TpmAIKHdl) + if err != nil { + return nil, nil, nil, err + } + + aikPubByte, err := aikPub.Encode() + if err != nil { + return nil, nil, nil, err + } + + aikNameMarshaled := &bytes.Buffer{} + if err := aikName.TPMMarshal(aikNameMarshaled); err != nil { + return nil, nil, nil, err + } + + return ekPubByte, aikPubByte, aikNameMarshaled.Bytes(), nil +} + +// handles the POST request /tmp/activate-credential/, this is used to activate +// the credential (decrypt the secret) using HWTPM EK and HWTPM AIK. +func activateCredntial(jsonData []byte) ([]byte, []byte, error) { + rw, err := tpm2.OpenTPM(etpm.TpmDevicePath) + if err != nil { + return nil, nil, err + } + defer rw.Close() + + var credPayload ActivateCredGenerated + if err := json.Unmarshal(jsonData, &credPayload); err != nil { + return nil, nil, err + } + + credBlob, err := base64.StdEncoding.DecodeString(credPayload.Cred) + if err != nil { + return nil, nil, err + } + + encryptedSecret, err := base64.StdEncoding.DecodeString(credPayload.Secret) + if err != nil { + return nil, nil, err + } + + // we need to skip the first 2 bytes of the credBlob and encryptedSecret + // as it contains the type. so make sure the length is greater than 2. + if len(credBlob) < 2 || len(encryptedSecret) < 2 { + return nil, nil, fmt.Errorf("malformed parameters") + } + credBlob = credBlob[2:] + encryptedSecret = encryptedSecret[2:] + + // activate the credential + recoveredCred, err := tpm2.ActivateCredential(rw, + etpm.TpmAIKHdl, + etpm.TpmEKHdl, + etpm.EmptyPassword, + etpm.EmptyPassword, + credBlob, + encryptedSecret) + if err != nil { + return nil, nil, err + } + + dataToSign, err := base64.StdEncoding.DecodeString(credPayload.Data) + if err != nil { + return nil, nil, err + } + + digest, validation, err := tpm2.Hash(rw, tpm2.AlgSHA256, dataToSign, tpm2.HandleOwner) + if err != nil { + return nil, nil, err + } + + sig, err := tpm2.Sign(rw, etpm.TpmAIKHdl, etpm.EmptyPassword, digest, validation, nil) + if err != nil { + return nil, nil, err + } + + return recoveredCred, sig.RSA.Signature, nil +} diff --git a/pkg/pillar/cmd/msrv/activatecred_test.go b/pkg/pillar/cmd/msrv/activatecred_test.go new file mode 100644 index 00000000000..53be6788aa2 --- /dev/null +++ b/pkg/pillar/cmd/msrv/activatecred_test.go @@ -0,0 +1,191 @@ +package msrv_test + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" + "time" + + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/legacy/tpm2/credactivation" + "github.com/lf-edge/eve/pkg/pillar/base" + "github.com/lf-edge/eve/pkg/pillar/cmd/msrv" + etpm "github.com/lf-edge/eve/pkg/pillar/evetpm" + "github.com/lf-edge/eve/pkg/pillar/pubsub" + "github.com/onsi/gomega" + "github.com/sirupsen/logrus" +) + +const TpmDevicePath = "/tmp/eve-tpm/srv.sock" + +var log = base.NewSourceLogObject(logrus.StandardLogger(), "test", 1234) + +func waitForTpmReadyState() error { + for i := 0; i < 10; i++ { + if err := etpm.SealDiskKey(log, []byte("secret"), etpm.DiskKeySealingPCRs); err != nil { + // this is RCRetry, so retry + if strings.Contains(err.Error(), "code 0x22") { + time.Sleep(100 * time.Millisecond) + continue + } else { + return fmt.Errorf("Something is wrong with the TPM : %w", err) + } + } else { + return nil + } + } + + return fmt.Errorf("TPM did't become ready after 10 attempts, failing the test") +} + +// TestTpmActivateCred contains TPM kong-fu, not for the faint of heart. +func TestTpmActivateCred(t *testing.T) { + _, err := os.Stat(TpmDevicePath) + if err != nil { + t.Skip("TPM is not available, skipping the test.") + } + + // for some reason testing SWTPM TPM might return RCRetry for the first + // few operations, so we need to wait for it to become ready. + if err := waitForTpmReadyState(); err != nil { + log.Fatalf("Failed to wait for TPM ready state: %v", err) + } + + t.Parallel() + g := gomega.NewGomegaWithT(t) + + logger := logrus.StandardLogger() + log := base.NewSourceLogObject(logger, "pubsub", 1234) + ps := pubsub.New(pubsub.NewMemoryDriver(), logger, log) + + srv := &msrv.Msrv{ + Log: log, + PubSub: ps, + Logger: logger, + } + + dir, err := os.MkdirTemp("/tmp", "msrv_test") + g.Expect(err).ToNot(gomega.HaveOccurred()) + defer os.RemoveAll(dir) + + err = srv.Init(dir, true) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + err = srv.Activate() + g.Expect(err).ToNot(gomega.HaveOccurred()) + + handler := srv.MakeMetadataHandler() + + // Get the activate credential parameters + pCred := httptest.NewRequest(http.MethodGet, "/eve/v1/tpm/activatecredential/", nil) + pCred.RemoteAddr = "192.168.1.1:0" + pCredRec := httptest.NewRecorder() + + handler.ServeHTTP(pCredRec, pCred) + defer pCredRec.Body.Reset() + g.Expect(pCredRec.Code).To(gomega.Equal(http.StatusOK)) + + var credParam msrv.ActivateCredTpmParam + err = json.Unmarshal(pCredRec.Body.Bytes(), &credParam) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + // Decode the EK back to tpm2.Public, in practices you need to find a + // way to trust EK using decive cert or OEM cert or whatever. + eKBytes, err := base64.StdEncoding.DecodeString(credParam.Ek) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + ekPub, err := tpm2.DecodePublic(eKBytes) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + // Decode the name back to name tpm2.Name + nameBytes, err := base64.StdEncoding.DecodeString(credParam.AikName) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + name, err := tpm2.DecodeName(bytes.NewBuffer(nameBytes)) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + // Decode the AIK back to tpm2.Public + aikBytes, err := base64.StdEncoding.DecodeString(credParam.AikPub) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + aikPub, err := tpm2.DecodePublic(aikBytes) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + // Verify the name matches the AIK + nameHash, err := name.Digest.Alg.Hash() + g.Expect(err).ToNot(gomega.HaveOccurred()) + + p, err := aikPub.Encode() + g.Expect(err).ToNot(gomega.HaveOccurred()) + + aikPubHash := nameHash.New() + aikPubHash.Write(p) + aikPubDigest := aikPubHash.Sum(nil) + g.Expect(bytes.Equal(name.Digest.Value, aikPubDigest)).To(gomega.BeTrue()) + + // Verify the AIK is a restricted signing key + g.Expect((aikPub.Attributes & tpm2.FlagFixedTPM)).To(gomega.BeEquivalentTo(tpm2.FlagFixedTPM)) + g.Expect((aikPub.Attributes & tpm2.FlagRestricted)).To(gomega.BeEquivalentTo(tpm2.FlagRestricted)) + g.Expect((aikPub.Attributes & tpm2.FlagFixedParent)).To(gomega.BeEquivalentTo(tpm2.FlagFixedParent)) + g.Expect((aikPub.Attributes & tpm2.FlagSensitiveDataOrigin)).To(gomega.BeEquivalentTo(tpm2.FlagSensitiveDataOrigin)) + + // Generate a credential + encKey, err := ekPub.Key() + g.Expect(err).ToNot(gomega.HaveOccurred()) + + dataToSign := []byte("Data to sign") + credential := make([]byte, 32) + rand.Read(credential) + symBlockSize := int(ekPub.RSAParameters.Symmetric.KeyBits) / 8 + credBlob, encryptedSecret, err := credactivation.Generate(name.Digest, encKey, symBlockSize, credential) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + var activeCredParam msrv.ActivateCredGenerated + activeCredParam.Cred = base64.StdEncoding.EncodeToString(credBlob) + activeCredParam.Secret = base64.StdEncoding.EncodeToString(encryptedSecret) + activeCredParam.Data = base64.StdEncoding.EncodeToString(dataToSign) + jsonStr, err := json.Marshal(activeCredParam) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + // Ask TPM to activate (decrypt) the credential + aCred := httptest.NewRequest(http.MethodPost, "/eve/v1/tpm/activatecredential/", bytes.NewBuffer(jsonStr)) + aCred.RemoteAddr = "192.168.1.1:0" + aCredRec := httptest.NewRecorder() + + handler.ServeHTTP(aCredRec, aCred) + defer aCredRec.Body.Reset() + g.Expect(aCredRec.Code).To(gomega.Equal(http.StatusOK)) + + var actCred msrv.ActivateCredActivated + err = json.Unmarshal(aCredRec.Body.Bytes(), &actCred) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + recovered, err := base64.StdEncoding.DecodeString(actCred.Secret) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + g.Expect(bytes.Equal(recovered, credential)).To(gomega.BeTrue()) + + // Verify the the signature + sig, err := base64.StdEncoding.DecodeString(actCred.Sig) + g.Expect(err).ToNot(gomega.HaveOccurred()) + + dataHash := crypto.SHA256.New() + dataHash.Write(dataToSign) + dataDigest := dataHash.Sum(nil) + + sinerPubKey, err := aikPub.Key() + g.Expect(err).ToNot(gomega.HaveOccurred()) + + sinerPub := sinerPubKey.(*rsa.PublicKey) + err = rsa.VerifyPKCS1v15(sinerPub, crypto.SHA256, dataDigest[:], sig) + g.Expect(err).ToNot(gomega.HaveOccurred()) +} diff --git a/pkg/pillar/cmd/msrv/handlers.go b/pkg/pillar/cmd/msrv/handlers.go index 75b8d72cbdd..72cddcb4dc5 100644 --- a/pkg/pillar/cmd/msrv/handlers.go +++ b/pkg/pillar/cmd/msrv/handlers.go @@ -709,3 +709,67 @@ func (msrv *Msrv) withPatchEnvelopesByIP() func(http.Handler) http.Handler { }) } } + +// handleActivateCredntial handles the request sign arbitrary data with HWTPM AIK, +// and proves that AIK resides in the HWTPM with the given HWTPM EK. +func (msrv *Msrv) handleActivateCredntial() func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet { + ekPubByte, aikPubByte, aiKnameMarshaled, err := getActivateCredntialParams() + if err != nil { + msrv.Log.Errorf("handleActivateCredntial: %v", err) + sendError(w, http.StatusInternalServerError, "Operation failed") + return + } + + activateCred := ActivateCredTpmParam{ + Ek: base64.StdEncoding.EncodeToString(ekPubByte), + AikPub: base64.StdEncoding.EncodeToString(aikPubByte), + AikName: base64.StdEncoding.EncodeToString(aiKnameMarshaled), + } + out, err := json.Marshal(activateCred) + if err != nil { + msrv.Log.Errorf("handleActivateCredntial: error marshaling JSON payload %v", err) + sendError(w, http.StatusInternalServerError, "Operation failed") + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(out) + return + + } else if r.Method == http.MethodPost { + in, err := io.ReadAll(io.LimitReader(r.Body, SignerMaxSize)) + if err != nil { + msrv.Log.Errorf("handleActivateCredntial, ReadAll : %v", err) + sendError(w, http.StatusInternalServerError, "Operation failed") + return + } + + cred, sig, err := activateCredntial(in) + if err != nil { + msrv.Log.Errorf("handleActivateCredntial, activateCredntial: %v", err) + sendError(w, http.StatusInternalServerError, "Operation failed") + return + } + + activateCred := ActivateCredActivated{ + Secret: base64.StdEncoding.EncodeToString(cred), + Sig: base64.StdEncoding.EncodeToString(sig), + } + out, err := json.Marshal(activateCred) + if err != nil { + msrv.Log.Errorf("handleActivateCredntial, error marshaling JSON payload : %v", err) + sendError(w, http.StatusInternalServerError, "Operation failed") + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(out) + return + } + + http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) + } +} diff --git a/pkg/pillar/cmd/msrv/msrv.go b/pkg/pillar/cmd/msrv/msrv.go index 2777bc1e8e6..ecde7c578a6 100644 --- a/pkg/pillar/cmd/msrv/msrv.go +++ b/pkg/pillar/cmd/msrv/msrv.go @@ -629,6 +629,9 @@ func (msrv *Msrv) MakeMetadataHandler() http.Handler { r.Post("/tpm/signer", msrv.handleSigner(&zedcloudCtx)) + r.Post("/tpm/activatecredential/", msrv.handleActivateCredntial()) + r.Get("/tpm/activatecredential/", msrv.handleActivateCredntial()) + r.Route("/patch", func(r chi.Router) { r.Use(msrv.withPatchEnvelopesByIP()) diff --git a/pkg/pillar/go.mod b/pkg/pillar/go.mod index 1b189b33edb..75cbb203d57 100644 --- a/pkg/pillar/go.mod +++ b/pkg/pillar/go.mod @@ -2,7 +2,6 @@ module github.com/lf-edge/eve/pkg/pillar go 1.22 - require ( github.com/anatol/smart.go v0.0.0-20220615232124-371056cd18c3 github.com/andrewd-zededa/go-libzfs v0.0.0-20240304231806-6a64e99da97d diff --git a/pkg/pillar/vendor/github.com/google/go-tpm/legacy/tpm2/credactivation/credential_activation.go b/pkg/pillar/vendor/github.com/google/go-tpm/legacy/tpm2/credactivation/credential_activation.go new file mode 100644 index 00000000000..90e9123d6ff --- /dev/null +++ b/pkg/pillar/vendor/github.com/google/go-tpm/legacy/tpm2/credactivation/credential_activation.go @@ -0,0 +1,206 @@ +// Copyright (c) 2018, Google LLC All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package credactivation implements generation of data blobs to be used +// when invoking the ActivateCredential command, on a TPM. +package credactivation + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "errors" + "fmt" + "io" + + "github.com/google/go-tpm/legacy/tpm2" + "github.com/google/go-tpm/tpmutil" +) + +// Labels for use in key derivation or OAEP encryption. +const ( + labelIdentity = "IDENTITY" + labelStorage = "STORAGE" + labelIntegrity = "INTEGRITY" +) + +// Generate returns a TPM2B_ID_OBJECT & TPM2B_ENCRYPTED_SECRET for use in +// credential activation. +// This has been tested on EKs compliant with TCG 2.0 EK Credential Profile +// specification, revision 14. +// The pub parameter must be a pointer to rsa.PublicKey. +// The secret parameter must not be longer than the longest digest size implemented +// by the TPM. A 32 byte secret is a safe, recommended default. +// +// This function implements Credential Protection as defined in section 24 of the TPM +// specification revision 2 part 1. +// See: https://trustedcomputinggroup.org/resource/tpm-library-specification/ +func Generate(aik *tpm2.HashValue, pub crypto.PublicKey, symBlockSize int, secret []byte) ([]byte, []byte, error) { + return generate(aik, pub, symBlockSize, secret, rand.Reader) +} + +func generate(aik *tpm2.HashValue, pub crypto.PublicKey, symBlockSize int, secret []byte, rnd io.Reader) ([]byte, []byte, error) { + var seed, encSecret []byte + var err error + switch ekKey := pub.(type) { + case *ecdh.PublicKey: + seed, encSecret, err = createECSeed(aik, ekKey, rnd) + if err != nil { + return nil, nil, fmt.Errorf("creating seed: %v", err) + } + case *ecdsa.PublicKey: + ecdhKey, err := ekKey.ECDH() + if err != nil { + return nil, nil, fmt.Errorf("transmuting ecdsa key to ecdh key: %v", err) + } + return generate(aik, ecdhKey, symBlockSize, secret, rnd) + case *rsa.PublicKey: + seed, encSecret, err = createRSASeed(aik, ekKey, symBlockSize, rnd) + if err != nil { + return nil, nil, fmt.Errorf("creating seed: %v", err) + } + default: + return nil, nil, errors.New("only RSA and EC public keys are supported for credential activation") + } + + // Generate the encrypted credential by convolving the seed with the digest of + // the AIK, and using the result as the key to encrypt the secret. + // See section 24.4 of TPM 2.0 specification, part 1. + aikNameEncoded, err := aik.Encode() + if err != nil { + return nil, nil, fmt.Errorf("encoding aikName: %v", err) + } + symmetricKey, err := tpm2.KDFa(aik.Alg, seed, labelStorage, aikNameEncoded, nil, symBlockSize*8) + if err != nil { + return nil, nil, fmt.Errorf("generating symmetric key: %v", err) + } + c, err := aes.NewCipher(symmetricKey) + if err != nil { + return nil, nil, fmt.Errorf("symmetric cipher setup: %v", err) + } + cv, err := tpmutil.Pack(tpmutil.U16Bytes(secret)) + if err != nil { + return nil, nil, fmt.Errorf("generating cv (TPM2B_Digest): %v", err) + } + + // IV is all null bytes. encIdentity represents the encrypted credential. + encIdentity := make([]byte, len(cv)) + cipher.NewCFBEncrypter(c, make([]byte, len(symmetricKey))).XORKeyStream(encIdentity, cv) + + // Generate the integrity HMAC, which is used to protect the integrity of the + // encrypted structure. + // See section 24.5 of the TPM 2.0 specification. + cryptohash, err := aik.Alg.Hash() + if err != nil { + return nil, nil, err + } + macKey, err := tpm2.KDFa(aik.Alg, seed, labelIntegrity, nil, nil, cryptohash.Size()*8) + if err != nil { + return nil, nil, fmt.Errorf("generating HMAC key: %v", err) + } + + mac := hmac.New(cryptohash.New, macKey) + mac.Write(encIdentity) + mac.Write(aikNameEncoded) + integrityHMAC := mac.Sum(nil) + + idObject := &tpm2.IDObject{ + IntegrityHMAC: integrityHMAC, + EncIdentity: encIdentity, + } + id, err := tpmutil.Pack(idObject) + if err != nil { + return nil, nil, fmt.Errorf("encoding IDObject: %v", err) + } + + packedID, err := tpmutil.Pack(tpmutil.U16Bytes(id)) + if err != nil { + return nil, nil, fmt.Errorf("packing id: %v", err) + } + packedEncSecret, err := tpmutil.Pack(tpmutil.U16Bytes(encSecret)) + if err != nil { + return nil, nil, fmt.Errorf("packing encSecret: %v", err) + } + + return packedID, packedEncSecret, nil +} + +func createRSASeed(aik *tpm2.HashValue, ek *rsa.PublicKey, symBlockSize int, rnd io.Reader) ([]byte, []byte, error) { + crypothash, err := aik.Alg.Hash() + if err != nil { + return nil, nil, err + } + + // The seed length should match the keysize used by the EKs symmetric cipher. + // For typical RSA EKs, this will be 128 bits (16 bytes). + // Spec: TCG 2.0 EK Credential Profile revision 14, section 2.1.5.1. + seed := make([]byte, symBlockSize) + if _, err := io.ReadFull(rnd, seed); err != nil { + return nil, nil, fmt.Errorf("generating seed: %v", err) + } + + // Encrypt the seed value using the provided public key. + // See annex B, section 10.4 of the TPM specification revision 2 part 1. + label := append([]byte(labelIdentity), 0) + encryptedSeed, err := rsa.EncryptOAEP(crypothash.New(), rnd, ek, seed, label) + if err != nil { + return nil, nil, fmt.Errorf("generating encrypted seed: %v", err) + } + + encryptedSeed, err = tpmutil.Pack(encryptedSeed) + return seed, encryptedSeed, err +} + +func createECSeed(ak *tpm2.HashValue, ek *ecdh.PublicKey, rnd io.Reader) (seed, encryptedSeed []byte, err error) { + ephemeralPriv, err := ek.Curve().GenerateKey(rnd) + if err != nil { + return nil, nil, err + } + ephemeralX, ephemeralY := deconstructECDHPublicKey(ephemeralPriv.PublicKey()) + + z, err := ephemeralPriv.ECDH(ek) + if err != nil { + return nil, nil, err + } + + ekX, _ := deconstructECDHPublicKey(ek) + + crypothash, err := ak.Alg.Hash() + if err != nil { + return nil, nil, err + } + + seed, err = tpm2.KDFe( + ak.Alg, + z, + labelIdentity, + ephemeralX, + ekX, + crypothash.Size()*8) + if err != nil { + return nil, nil, err + } + encryptedSeed, err = tpmutil.Pack(tpmutil.U16Bytes(ephemeralX), tpmutil.U16Bytes(ephemeralY)) + return seed, encryptedSeed, err +} + +func deconstructECDHPublicKey(key *ecdh.PublicKey) (x []byte, y []byte) { + b := key.Bytes()[1:] + return b[:len(b)/2], b[len(b)/2:] +} diff --git a/pkg/pillar/vendor/modules.txt b/pkg/pillar/vendor/modules.txt index ce755a9dce5..3e555864d99 100644 --- a/pkg/pillar/vendor/modules.txt +++ b/pkg/pillar/vendor/modules.txt @@ -495,6 +495,7 @@ github.com/google/go-containerregistry/pkg/v1/types # github.com/google/go-tpm v0.9.1 ## explicit; go 1.22 github.com/google/go-tpm/legacy/tpm2 +github.com/google/go-tpm/legacy/tpm2/credactivation github.com/google/go-tpm/tpmutil github.com/google/go-tpm/tpmutil/tbs # github.com/google/gofuzz v1.2.0 diff --git a/tests/tpm/prep-and-test.sh b/tests/tpm/prep-and-test.sh index 94bd09920e3..325d558c2ee 100755 --- a/tests/tpm/prep-and-test.sh +++ b/tests/tpm/prep-and-test.sh @@ -7,8 +7,10 @@ # add more TPM tests here TESTS=( "/pillar/evetpm" + "/pillar/cmd/msrv" ) +CWD=$(pwd) TPM_SRV_PORT=1337 TPM_CTR_PORT=$((TPM_SRV_PORT + 1)) ENDO_SEED=0x4000000B @@ -103,5 +105,5 @@ echo "[+] Running tests ..." echo "========================================================" for T in "${TESTS[@]}"; do name=$(basename "$T") - cd pkg$T && go test -v -coverprofile="$name.coverage.txt" -covermode=atomic + cd "$CWD/pkg$T" && go test -v -coverprofile="$name.coverage.txt" -covermode=atomic done