Repository navigation
Expand file tree
/
Copy pathcmds_session.go
More file actions
192 lines (173 loc) · 9.23 KB
/
Copy pathcmds_session.go
File metadata and controls
192 lines (173 loc) · 9.23 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2019 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package tpm2
// Section 11 - Session Commands
import (
"fmt"
internal_crypt "github.com/canonical/go-tpm2/internal/crypt"
)
// StartAuthSession executes the TPM2_StartAuthSession command to start an authorization session.
// On successful completion, it will return a SessionContext that corresponds to the new session.
//
// The type of session is defined by the sessionType parameter. If sessionType is
// [SessionTypeHMAC] or [SessionTypePolicy], then the created session may be used for
// authorization. If sessionType is [SessionTypeTrial], then the created session can only be used
// for computing an authorization policy digest.
//
// The authHash parameter defines the algorithm used for computing command and response parameter
// digests, command and response HMACs, and derivation of the session key and symmetric keys for
// parameter encryption where used. The size of the digest algorithm is used to determine the nonce
// size used for the session.
//
// If tpmKey is provided then a salted session is created. In this case, it must be possible to
// type assert the provided key to [ObjectContext]. The key must correspond to an asymmetric
// decrypt key in the TPM - it must have a type of [ObjectTypeRSA] or [ObjectTypeECC] and it must
// have the [AttrDecrypt] attribute set. In this case, a random salt value will be established
// which will contribute to the session key derivation. If tpmKey has the type of [ObjectTypeRSA],
// the random salt will be created on the host and RSA-OAEP encrypted with the public part of
// tpmKey before being sent to the TPM. If tpmKey has the type of [ObjectTypeECC], a random salt
// is established using ECDH key exchange and an ephemeral host key. If tpmKey is provided but does
// not correspond to an asymmetric key, a *[TPMHandleError] error with an error code of [ErrorKey]
// will be returned for handle index 1. If tpmKey is provided but corresponds to an object with only
// its public part loaded, a *[TPMHandleError] error with an error code of [ErrorHandle] will be
// returned for handle index 1. If tpmKey is provided but does not correspond to a decrypt key, a
// *[TPMHandleError] error with an error code of [ErrorAttributes] will be returned for handle
// index 1.
//
// If tpmkey is provided but establishment of the salt fails on the TPM, a *[TPMParameterError]
// error with an error code of [ErrorValue] or [ErrorKey] may be returned for parameter index 2.
//
// If tpmKey is not provided, an unsalted session is created.
//
// If bind is specified then a bound session is created. The authorization value for the
// corresponding bind resource must be known, by calling [ResourceContext].SetAuthValue on bind
// before calling this function. In this case, the authorization value will contribute to the
// session key derivation. The created session will be bound to the resource associated with bind,
// unless the authorization value of that resource is subsequently changed. If bind corresponds to
// a transient object and only the public part of the object is loaded, or if bind corresponds to
// a NV index with a type of [NVTypePinPass] or [NVTypePinFail], a *[TPMHandleError] error with an
// error code of [ErrorHandle] will be returned for handle index 2.
//
// If tpmKey or bind is specified, a session key is computed. If neither tpmKey or bind are
// specified, then no session key is computed.
//
// When the created session is used for authorization, a HMAC key used to generate and verify
// command and response HMACs is created. If the session is used for authorization of the bound
// resource, then the HMAC key is generated from the session key if there is one. If the session is
// used for authorization of any other resource, then the HMAC key is generated from the session
// key (if there is one) and the authorization value of the resource that the session is being used
// for authorization of.
//
// If symmetric is provided, it defines the symmetric algorithm to use if the session is
// subsequently used for session based command or response parameter encryption. Session based
// parameter encryption allows the first command and/or response parameter for a command to be
// encrypted between the TPM and host CPU for supported parameter types (go types that correspond
// to TPM2B prefixed types). If symmetric is provided and corresponds to a symmetric block cipher
// (ie, the Algorithm field is not [SymAlgorithmXOR]) then the symmetric mode must be
// [SymModeCFB], else a *[TPMParameterError] error with an error code of [ErrorMode] is returned
// for parameter index 4.
//
// When the created session is used for parameter encryption, the encryption key is derived from
// the session key if there is one. If the session is also used for authorization, then the
// encryption key derivation also uses the authorization value of the resource that the session is
// being used for authorization of, regardless of whether it is bound to it.
//
// If a SessionContext instance with the [AttrCommandEncrypt] attribute set is provided in the
// variable length sessions parameter, then the initial caller nonce will be encrypted as this is
// the first command parameter, despite not being exposed via this API. If a SessionContext
// instance with the AttrResponseEncrypt attribute set is provided, then the initial TPM nonce will
// be encrypted in the response.
//
// If sessionType is [SessionTypeHMAC] and the session is subsequently used for authorization of a
// resource to which the session is not bound, the authorization value of that resource must be
// known as it is used to derive the key for computing command and response HMACs.
//
// If no more sessions can be created without first context loading the oldest saved session, then
// a *[TPMWarning] error with a warning code of [WarningContextGap] will be returned. If there are
// no more slots available for loaded sessions, a *[TPMWarning] error with a warning code of
// [WarningSessionMemory] will be returned. If there are no more session handles available, a
// *[TPMwarning] error with a warning code of [WarningSessionHandles] will be returned.
func (t *TPMContext) StartAuthSession(tpmKey, bind ResourceContext, sessionType SessionType, symmetric *SymDef, authHash HashAlgorithmId, sessions ...SessionContext) (sessionContext SessionContext, err error) {
if symmetric == nil {
symmetric = &SymDef{Algorithm: SymAlgorithmNull}
}
if !authHash.Available() {
return nil, makeInvalidArgError("authHash", fmt.Sprintf("unsupported digest algorithm or algorithm not linked in to binary (%v)", authHash))
}
digestSize := authHash.Size()
var salt []byte
var encryptedSalt EncryptedSecret
tpmKeyHandle := HandleNull
if tpmKey != nil {
object, isObject := tpmKey.(ObjectContext)
if !isObject {
return nil, makeInvalidArgError("tpmKey", "resource context is not an object")
}
if object.Public() == nil {
return nil, makeInvalidArgError("tpmKey", "no public area")
}
tpmKeyHandle = tpmKey.Handle()
var err error
encryptedSalt, salt, err = cryptSecretEncrypt(object.Public(), []byte(SecretKey))
if err != nil {
return nil, fmt.Errorf("cannot compute encrypted salt: %v", err)
}
}
var authValue []byte
bindHandle := HandleNull
if bind != nil {
bindHandle = bind.Handle()
authValue = trimAuthValue(bind.AuthValue())
}
var isBound bool = false
var boundEntity Name
if bindHandle != HandleNull && sessionType == SessionTypeHMAC {
boundEntity = computeBindName(bind.Name(), authValue)
isBound = true
}
nonceCaller := make([]byte, digestSize)
if err := cryptComputeNonce(nonceCaller); err != nil {
return nil, fmt.Errorf("cannot compute initial nonceCaller: %v", err)
}
var sessionHandle Handle
var nonceTPM Nonce
if err := t.StartCommand(CommandStartAuthSession).
AddHandles(UseHandleContext(tpmKey), UseHandleContext(bind)).
AddParams(Nonce(nonceCaller), encryptedSalt, sessionType, symmetric, authHash).
AddExtraSessions(sessions...).
Run(&sessionHandle, &nonceTPM); err != nil {
return nil, err
}
switch sessionHandle.Type() {
case HandleTypeHMACSession, HandleTypePolicySession:
default:
return nil, &InvalidResponseError{CommandStartAuthSession,
fmt.Errorf("handle 0x%08x returned from TPM is the wrong type", sessionHandle)}
}
data := &sessionContextData{
Params: SessionContextParams{
HashAlg: authHash,
IsBound: isBound,
BoundEntity: boundEntity,
Symmetric: *symmetric,
},
State: SessionContextState{
NonceTPM: nonceTPM,
}}
if tpmKeyHandle != HandleNull || bindHandle != HandleNull {
key := make([]byte, len(authValue)+len(salt))
copy(key, authValue)
copy(key[len(authValue):], salt)
data.Params.SessionKey = internal_crypt.KDFa(authHash.GetHash(), key, []byte(SessionKey), []byte(nonceTPM), nonceCaller, digestSize*8)
}
return newSessionContext(sessionHandle, data), nil
}
// PolicyRestart executes the TPM2_PolicyRestart command on the policy session associated with
// sessionContext, to reset the policy authorization session to its initial state.
func (t *TPMContext) PolicyRestart(sessionContext SessionContext, sessions ...SessionContext) error {
return t.StartCommand(CommandPolicyRestart).
AddHandles(UseHandleContext(sessionContext)).
AddExtraSessions(sessions...).
Run(nil)
}