@@ -9,12 +9,14 @@ import (
9
9
"crypto/ecdsa"
10
10
"crypto/x509"
11
11
"encoding/asn1"
12
+ "encoding/gob"
12
13
"encoding/pem"
13
14
"fmt"
14
15
"io"
15
16
"io/ioutil"
16
17
"math/big"
17
18
"os"
19
+ "sort"
18
20
"unsafe"
19
21
20
22
"github.com/google/go-tpm/tpm2"
@@ -71,6 +73,10 @@ const (
71
73
//EmptyPassword is an empty string
72
74
EmptyPassword = ""
73
75
vaultKeyLength = 32 //Bytes
76
+
77
+ // TpmSavedDiskSealingPcrs is the file that holds a copy of PCR values
78
+ // at the time of generating and sealing the disk key into the TPM.
79
+ TpmSavedDiskSealingPcrs = types .PersistStatusDir + "/sealingpcrs"
74
80
)
75
81
76
82
// PCRBank256Status stores info about support for
@@ -612,6 +618,12 @@ func SealDiskKey(key []byte, pcrSel tpm2.PCRSelection) error {
612
618
EmptyPassword , public , 0 ); err != nil {
613
619
return fmt .Errorf ("NVWrite %v failed: %v" , TpmSealedDiskPubHdl , err )
614
620
}
621
+
622
+ // save a snapshot of PCR values
623
+ if err := saveDiskKeySealingPCRs (TpmSavedDiskSealingPcrs ); err != nil {
624
+ return fmt .Errorf ("saving snapshot of sealing PCRs failed: %v" , err )
625
+ }
626
+
615
627
return nil
616
628
}
617
629
@@ -667,7 +679,14 @@ func UnsealDiskKey(pcrSel tpm2.PCRSelection) ([]byte, error) {
667
679
668
680
key , err := tpm2 .UnsealWithSession (rw , session , sealedObjHandle , EmptyPassword )
669
681
if err != nil {
670
- return nil , fmt .Errorf ("UnsealWithSession failed: %v" , err )
682
+ // We get here mostly because of RCPolicyFail error, so try to get more
683
+ // information about the failure by finding the mismatching PCR index.
684
+ mismatch , newErr := findMismatchingPCRs (TpmSavedDiskSealingPcrs )
685
+ if newErr != nil {
686
+ return nil , fmt .Errorf ("UnsealWithSession failed: %v, failed to get more info: %v" , err , newErr )
687
+ }
688
+
689
+ return nil , fmt .Errorf ("UnsealWithSession failed: %v, possibly mismatching PCR indexes %v" , err , mismatch )
671
690
}
672
691
return key , nil
673
692
}
@@ -776,3 +795,88 @@ func pcrBankSHA256EnabledHelper() bool {
776
795
_ , err = tpm2 .ReadPCR (rw , 0 , tpm2 .AlgSHA256 )
777
796
return err == nil
778
797
}
798
+
799
+ func saveDiskKeySealingPCRs (pcrsFile string ) error {
800
+ trw , err := tpm2 .OpenTPM (TpmDevicePath )
801
+ if err != nil {
802
+ return err
803
+ }
804
+ defer trw .Close ()
805
+
806
+ readPCRs , err := readDiskKeySealingPCRs ()
807
+ if err != nil {
808
+ return err
809
+ }
810
+
811
+ frw , err := os .Create (pcrsFile )
812
+ if err != nil {
813
+ return err
814
+ }
815
+ defer frw .Close ()
816
+
817
+ e := gob .NewEncoder (frw )
818
+ err = e .Encode (readPCRs )
819
+ if err != nil {
820
+ return err
821
+ }
822
+
823
+ return nil
824
+ }
825
+
826
+ func findMismatchingPCRs (savedPCRsFile string ) ([]int , error ) {
827
+ frw , err := os .Open (savedPCRsFile )
828
+ if err != nil {
829
+ return nil , err
830
+ }
831
+ defer frw .Close ()
832
+
833
+ var savedPCRs map [int ][]byte
834
+ d := gob .NewDecoder (frw )
835
+ err = d .Decode (& savedPCRs )
836
+ if err != nil {
837
+ return nil , err
838
+ }
839
+
840
+ readPCRs , err := readDiskKeySealingPCRs ()
841
+ if err != nil {
842
+ return nil , err
843
+ }
844
+
845
+ mismatch := make ([]int , 0 )
846
+ for i , savedPCR := range savedPCRs {
847
+ readPCR , ok := readPCRs [i ]
848
+ // this should never happen, except when we update EVE and adding new
849
+ // indexes to the DiskKeySealingPCRs, anyways, better safe than sorry!
850
+ if ! ok {
851
+ return nil , fmt .Errorf ("saved PCR index %d doesn't exist at run-time PCRs list %v" , i , DiskKeySealingPCRs .PCRs )
852
+ }
853
+
854
+ if ! bytes .Equal (readPCR , savedPCR ) {
855
+ mismatch = append (mismatch , i )
856
+ }
857
+ }
858
+
859
+ sort .Ints (mismatch )
860
+ return mismatch , nil
861
+ }
862
+
863
+ func readDiskKeySealingPCRs () (map [int ][]byte , error ) {
864
+ rw , err := tpm2 .OpenTPM (TpmDevicePath )
865
+ if err != nil {
866
+ return nil , err
867
+ }
868
+ defer rw .Close ()
869
+
870
+ // tpm2.ReadPCRs returns at most 8 PCRs, so loop over and read one by one
871
+ readPCRs := make (map [int ][]byte )
872
+ for _ , v := range DiskKeySealingPCRs .PCRs {
873
+ p , err := tpm2 .ReadPCR (rw , v , DiskKeySealingPCRs .Hash )
874
+ if err != nil {
875
+ return nil , err
876
+ }
877
+
878
+ readPCRs [v ] = p
879
+ }
880
+
881
+ return readPCRs , nil
882
+ }
0 commit comments