@@ -43,6 +43,12 @@ type VTPM struct {
4343 // Set of active PCR banks
4444 PcrBanks string `json:"pcrbanks"`
4545
46+ // plain text encryption password used by vTPM
47+ encryptionPassword []byte
48+
49+ // whether an error occurred writing the password to the pipe
50+ passwordPipeError error
51+
4652 // The user under which to run the TPM emulator
4753 user string
4854
@@ -182,7 +188,7 @@ func hasCapability(capabilities []string, capability string) bool {
182188// with account tss; TPM 2 has more flexibility
183189//
184190// After successful creation of the object the Start() method can be called
185- func NewVTPM (statepath string , statepathismanaged bool , vtpmversion string , createcerts bool , runas string , pcrbanks string ) (* VTPM , error ) {
191+ func NewVTPM (statepath string , statepathismanaged bool , vtpmversion string , createcerts bool , runas string , pcrbanks string , encryptionpassword [] byte ) (* VTPM , error ) {
186192 if len (statepath ) == 0 {
187193 return nil , fmt .Errorf ("Missing required statpath for vTPM." )
188194 }
@@ -231,6 +237,7 @@ func NewVTPM(statepath string, statepathismanaged bool, vtpmversion string, crea
231237 Vtpmversion : vtpmversion ,
232238 CreateCerts : createcerts ,
233239 PcrBanks : pcrbanks ,
240+ encryptionPassword : encryptionpassword ,
234241 Tpm_dev_num : VTPM_DEV_NUM_INVALID ,
235242 fd : ILLEGAL_FD ,
236243 swtpmSetupCaps : swtpmSetupCaps ,
@@ -453,6 +460,34 @@ func (vtpm *VTPM) chownStatePath() error {
453460 return nil
454461}
455462
463+ // setup the password pipe so that we can transfer the TPM state encryption via
464+ // a pipe where the read-end is passed to swtpm / swtpm_setup as a file descriptor
465+ func (vtpm * VTPM ) setupPasswordPipe (password []byte ) (* os.File , error ) {
466+ if ! hasCapability (vtpm .swtpmSetupCaps , "cmdarg-pwdfile-fd" ) {
467+ return nil , fmt .Errorf ("Requiring newer version of swtpm for state encryption; needs cmdarg-pwd-fd feature" )
468+ }
469+
470+ piper , pipew , err := os .Pipe ()
471+ if err != nil {
472+ return nil , fmt .Errorf ("Could not create pipe" )
473+ }
474+ vtpm .passwordPipeError = nil
475+
476+ go func () {
477+ tot := 0
478+ for tot < len (password ) {
479+ var n int
480+ n , vtpm .passwordPipeError = pipew .Write (password )
481+ if vtpm .passwordPipeError != nil {
482+ break
483+ }
484+ tot = tot + n
485+ }
486+ pipew .Close ()
487+ }()
488+ return piper , nil
489+ }
490+
456491// runSwtpmSetup runs swtpm_setup to simulate TPM manufacturing by creating
457492// EK and platform certificates and enabling TPM 2 PCR banks
458493func (vtpm * VTPM ) runSwtpmSetup () error {
@@ -470,6 +505,16 @@ func (vtpm *VTPM) runSwtpmSetup() error {
470505 if vtpm .CreateCerts {
471506 cmd .Args = append (cmd .Args , "--create-ek-cert" , "--create-platform-cert" , "--lock-nvram" )
472507 }
508+ if len (vtpm .encryptionPassword ) > 0 {
509+ piper , err := vtpm .setupPasswordPipe (vtpm .encryptionPassword )
510+ if err != nil {
511+ return err
512+ }
513+ cmd .ExtraFiles = append (cmd .ExtraFiles , piper )
514+ pwdfile_fd := fmt .Sprintf ("%d" , 3 + len (cmd .ExtraFiles )- 1 )
515+ cmd .Args = append (cmd .Args , "--cipher" , "aes-256-cbc" , "--pwdfile-fd" , pwdfile_fd )
516+ defer piper .Close ()
517+ }
473518
474519 if vtpm .Vtpmversion == VTPM_VERSION_2 {
475520 cmd .Args = append (cmd .Args , "--tpm2" )
@@ -488,6 +533,10 @@ func (vtpm *VTPM) runSwtpmSetup() error {
488533 return fmt .Errorf ("swtpm_setup failed: %s\n log: %s" , string (output ), vtpm .ReadLog ())
489534 }
490535
536+ if vtpm .passwordPipeError != nil {
537+ return fmt .Errorf ("Error transferring password using pipe: %v" , vtpm .passwordPipeError )
538+ }
539+
491540 return nil
492541}
493542
@@ -548,10 +597,24 @@ func (vtpm *VTPM) startSwtpm() error {
548597 file := os .NewFile (uintptr (vtpm .fd ), "[vtpm]" )
549598 cmd .ExtraFiles = append (cmd .ExtraFiles , file )
550599
600+ if len (vtpm .encryptionPassword ) > 0 {
601+ piper , err := vtpm .setupPasswordPipe (vtpm .encryptionPassword )
602+ if err != nil {
603+ return err
604+ }
605+ cmd .ExtraFiles = append (cmd .ExtraFiles , piper )
606+ cmd .Args = append (cmd .Args , "--key" ,
607+ fmt .Sprintf ("pwdfd=%d,mode=aes-256-cbc,kdf=pbkdf2" , 3 + len (cmd .ExtraFiles )- 1 ))
608+ defer piper .Close ()
609+ }
610+
551611 output , err := cmd .CombinedOutput ()
552612 if err != nil {
553613 return fmt .Errorf ("swtpm failed on fd %d: %s\n log: %s" , vtpm .fd , string (output ), vtpm .ReadLog ())
554614 }
615+ if vtpm .passwordPipeError != nil {
616+ return fmt .Errorf ("Error transferring password using pipe: %v" , vtpm .passwordPipeError )
617+ }
555618
556619 vtpm .Pid , err = vtpm .waitForPidFile (10 )
557620 if err != nil {
0 commit comments