-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathsealed_object_example_test.go
146 lines (119 loc) · 3.91 KB
/
sealed_object_example_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2022 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package tpm2_test
import (
"fmt"
"os"
"github.com/canonical/go-tpm2"
"github.com/canonical/go-tpm2/linux"
"github.com/canonical/go-tpm2/mu"
"github.com/canonical/go-tpm2/objectutil"
"github.com/canonical/go-tpm2/util"
)
// srkHandle defines the handle for the SRK
const srkHandle = 0x81000001
// seal protects the supplied secret in the storage hierarchy of the TPM using
// a simple authorization policy that is gated on the current values of the PCRs
// included in the specified selection. The sealed object and metadata are
// serialized and returned in a form that can be passed to the unseal function.
func seal(secret []byte, pcrSelection tpm2.PCRSelectionList) ([]byte, error) {
device, err := linux.DefaultTPM2Device()
if err != nil {
return nil, err
}
tpm, err := tpm2.OpenTPMDevice(device)
if err != nil {
return nil, err
}
defer tpm.Close()
// Use the shared SRK as the storage object, and assume that it already exists.
srk, err := tpm.NewResourceContext(srkHandle)
if err != nil {
return nil, err
}
// Build the sealed object template
template := objectutil.NewSealedObjectTemplate(
objectutil.WithUserAuthMode(objectutil.RequirePolicy))
// Compute a simple PCR policy using the TPM's current values
_, values, err := tpm.PCRRead(pcrSelection)
if err != nil {
return nil, err
}
digest, err := util.ComputePCRDigest(tpm2.HashAlgorithmSHA256, pcrSelection, values)
if err != nil {
return nil, err
}
trial := util.ComputeAuthPolicy(tpm2.HashAlgorithmSHA256)
trial.PolicyPCR(digest, pcrSelection)
template.AuthPolicy = trial.GetDigest()
sensitive := &tpm2.SensitiveCreate{Data: secret}
// Create the sealed object
priv, pub, _, _, _, err := tpm.Create(srk, sensitive, template, nil, nil, nil)
if err != nil {
return nil, err
}
// Encode and return the sealed object
return mu.MarshalToBytes(priv, pub, pcrSelection)
}
// unseal attempts to recover a secret from the supplied blob previously created by the seal
// function.
func unseal(data []byte) ([]byte, error) {
// Decode the sealed object
var priv tpm2.Private
var pub *tpm2.Public
var pcrSelection tpm2.PCRSelectionList
if _, err := mu.UnmarshalFromBytes(data, &priv, &pub, &pcrSelection); err != nil {
return nil, err
}
device, err := linux.DefaultTPM2Device()
if err != nil {
return nil, err
}
tpm, err := tpm2.OpenTPMDevice(device)
if err != nil {
return nil, err
}
defer tpm.Close()
srk, err := tpm.NewResourceContext(srkHandle)
if err != nil {
return nil, err
}
// Load the sealed object into the TPM
object, err := tpm.Load(srk, priv, pub, nil)
if err != nil {
return nil, err
}
defer tpm.FlushContext(object)
// Run a policy session with the PCR assertion
session, err := tpm.StartAuthSession(nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)
if err != nil {
return nil, err
}
defer tpm.FlushContext(session)
if err := tpm.PolicyPCR(session, nil, pcrSelection); err != nil {
return nil, err
}
return tpm.Unseal(object, session)
}
func Example_sealingASecret() {
// Seal a secret to the storage hierarchy of the TPM using an authorization policy
// that is gated on the current value of PCR7.
//
// Don't assume that this is a secure way to protect a key - it's just an example!
secret := []byte("secret data")
pcrSelection := tpm2.PCRSelectionList{{Hash: tpm2.HashAlgorithmSHA256, Select: []int{7}}}
sealedData, err := seal(secret, pcrSelection)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot seal:", err)
return
}
// sealedData contains a serialized blob containing our secret that has been protected by the
// TPM. It could be written somewhere to be read back later on.
recoveredSecret, err := unseal(sealedData)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot unseal:", err)
return
}
fmt.Println("recovered secret:", recoveredSecret)
}