{"record":{"id":"dac6e37cf3f5ef5c","repo":"pulumi/pulumi","slug":"sealing-key-in-tpm-w","errorCode":null,"errorMessage":"sealing key in TPM: %w","messagePattern":"sealing key in TPM: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/common/util/securestore/tpm.go","lineNumber":149,"sourceCode":"\t\t\treturn nil, err\n\t\t}\n\t\tdefer flushHandle(tpm, primary.ObjectHandle)\n\n\t\trsp, err := tpm2.Create{\n\t\t\tParentHandle: tpm2.AuthHandle{\n\t\t\t\tHandle: primary.ObjectHandle,\n\t\t\t\tName:   primary.Name,\n\t\t\t\tAuth:   tpm2.PasswordAuth(nil),\n\t\t\t},\n\t\t\tInSensitive: tpm2.TPM2BSensitiveCreate{\n\t\t\t\tSensitive: &tpm2.TPMSSensitiveCreate{\n\t\t\t\t\tData: tpm2.NewTPMUSensitiveCreate(&tpm2.TPM2BSensitiveData{Buffer: key}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tInPublic: tpm2.New2B(sealedDataTemplate()),\n\t\t}.Execute(tpm)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sealing key in TPM: %w\", err)\n\t\t}\n\t\treturn encodeSealedBlob(tpm2.Marshal(rsp.OutPrivate), tpm2.Marshal(rsp.OutPublic))\n\t})\n}\n\n// unwrap recovers the key from a blob produced by wrap: it regenerates the\n// same storage primary, loads the sealed object under it, and unseals it.\nfunc (tpmWrapper) unwrap(blob []byte) ([]byte, error) {\n\tprivBytes, pubBytes, err := decodeSealedBlob(blob)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpriv, err := tpm2.Unmarshal[tpm2.TPM2BPrivate](privBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"stored key is corrupt (bad TPM private blob): %w\", err)\n\t}\n\tpub, err := tpm2.Unmarshal[tpm2.TPM2BPublic](pubBytes)\n\tif err != nil {","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/common/util/securestore/tpm.go#L131-L167","documentation":"tpmWrapper.wrap executes tpm2.Create to seal the key as a keyedhash SEALED-DATA object under the storage primary. If the TPM rejects the Create command, the error is wrapped as 'sealing key in TPM'. This is distinct from openTPM failures: the TPM is reachable but refuses the seal operation.","triggerScenarios":"tpm2.Create{ParentHandle: owner primary, InSensitive: key}.Execute returning a TPM error: owner hierarchy locked (dictionary-attack lockout), primary handle lost mid-session, out of transient object slots, or transport error during the command.","commonSituations":"TPM dictionary-attack lockout state; TPM transient memory exhausted by other applications' loaded objects; firmware quirks with the ECC SRK parent; device error mid-operation on a shared TPM.","solutions":["Inspect the wrapped TPM return code; TPM_RC_LOCKOUT means wait out the dictionary-attack lockout period.","Retry — transient object exhaustion frees up as other clients flush handles.","Reboot or reset the TPM if the owner hierarchy is in a bad state (note: clearing the TPM destroys existing sealed keys).","Confirm no non-empty owner auth was set on the TPM; pulumi authenticates with an empty password.","Fall back to PULUMI_CREDENTIAL_STORE=plaintext or an OS-store backend if the TPM cannot seal."],"exampleFix":"# probe TPM health\nsudo tpm2_getcap properties-fixed\nsudo tpm2_getcap handles-transient   # check for object-slot exhaustion\n# if locked out, wait; clearing the TPM destroys sealed keys\nsudo tpm2_clear -a p","handlingStrategy":"retry","validationCode":"// Ensure the TPM can create the primary first (proves owner hierarchy usable)\nif err := (tpmWrapper{}).available(); err != nil { /* pick another backend before sealing */ }","typeGuard":"func isSealFailure(err error) bool { return strings.Contains(err.Error(), \"sealing key in TPM\") }","tryCatchPattern":"blob, err := wrapper.wrap(key)\nif err != nil {\n    if strings.Contains(err.Error(), \"TPM_RC_LOCKOUT\") {\n        // wait out dictionary-attack lockout, then retry once\n    }\n    return fmt.Errorf(\"TPM seal failed; falling back: %w\", err)\n}","preventionTips":["Wait out dictionary-attack lockout periods instead of hammering the TPM","Watch for transient-object exhaustion on TPMs shared with other applications","Keep TPM firmware updated; reboot to reset a wedged owner hierarchy","Keep an OS-store or plaintext fallback path for machines where sealing fails repeatedly"],"tags":["go","tpm","sealing","hardware"],"backgroundTag":"tpm-command-failed","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}