Desktop version

Home arrow Computer Science arrow A Practical Guide to TPM 2.0

HMAC and Policy Session Code Example

Listing 13-2 presents a simple example of how to execute HMAC and policy sessions. This function is known to work, and all of its support routines are available in the TSS SAPI test code described in Chapter 7. To keep the code as simple as possible, it uses an unbound and unsalted session. If you'd like to see more complicated examples, all variations of bound/unbound and salted/unsalted are tested in the HmacSessionTest in the TSS SAPI test code.

Note

Managing hMaC sessions and calculating hMaC authorizations are complicated tasks. some of the functions called in Listing 13-2 are only explained at a high level. the goal was to demonstrate the high-level flow of an hMaC authorization without overwhelmingyou with low-level details. if you want to dig deeper, the source code for all the subroutines is available at the web site noted for the tss sapi test code in Chapter 7.

To help compare HMAC and policy sessions, this code does HMAC or policy authorizations, depending on the value of the hmacTest input parameter; if conditional statements using the hmacTest parameter are used for all the HMACor policy-specific code. For now, because this section is about HMAC authorizations, ignore all the parts of the code that only pertain to policy sessions (these areas are shaded).

Some notes about this code:

• The code does a write to an NV index followed by a read of the same NV index. Both the read and write are authorized using an HMAC authorization.

• To authorize the read and write operations, this code uses either an HMAC session or a policy session with a TPM2_ PolicyAuthValue command. This provides similar capability

(both sessions use an HMAC for authorization), and thus provides a useful vehicle for comparing HMAC and policy sessions.

• The RollNonces function does what it says: it copies nonceNewer to nonceOlder and copies the new nonce to nonceNewer. The nonces must be rolled before each command and after each response. This is described more in the section “Using an HMAC Session to Send Multiple Commands (Rolling Nonces).” Here's the complete code for this function:

void RollNonces( SESSION *session, TPM2B_NONCE *newNonce )

{session->nonceOlder = session->nonceNewer; session->nonceNewer = *newNonce;}

this code example uses a single byte nonceCaller for both the nV write and read commands. this isn't a recommended usage—typically, to maximize replay protection, you would use a nonce that is the size of the session's selected hash algorithm, and you would use different randomly generated nonces for each command being authorized.

• This code relies heavily on an application-level structure, SESSION, that maintains all session state information including nonces. There are many ways this can be done—this just happens to be the implementation I chose. This structure looks like this:

typedef struct {// Inputs to StartAuthSession; these need to be saved// so that HMACs can be calculated. TPMI_DH_OBJECT tpmKey; TPMI_DH_ENTITY bind;

TPM2B_ENCRYPTED_SECRET encryptedSalt; TPM2B_MAX_BUFFER salt;

TPM_SE sessionType; TPMT_SYM_DEF symmetric; TPMI_ALG_HASH authHash;

// Outputs from StartAuthSession; these also need

// to be saved for calculating HMACs and

// other session related functions. TPMI_SH_AUTH_SESSION sessionHandle; TPM2B_NONCE nonceTPM;

// Internal state for the session TPM2B_DIGEST sessionKey;

TPM2B_DIGEST authValueBind; // authValue of bind object TPM2B_NONCE nonceNewer;

TPM2B_NONCE nonceOlder; TPM2B_NONCE nonceTpmDecrypt; TPM2B_NONCE nonceTpmEncrypt;

TPM2B_NAME name; // Name of the object the session handle

// points to. Used for computing HMAC for

// any HMAC sessions present.

// void *hmacPtr;

// Pointer to HMAC field in the marshalled

// data stream for the session.

// This allows the function to calculate

// and fill in the HMAC after marshalling

// of all the inputs is done.

//// This is only used if the session is an

// HMAC session.

//UINT8 nvNameChanged;// Used for some special case code

// dealing with the NV written state.} SESSION;

• StartAuthSessionWithParams starts the session, saves its state in a SESSION structure, and adds the SESSION structure to the application's list of open sessions.

• EndAuthSession is used to remove the SESSION structure from the application's list of open sessions after the session has ended.

Listing 13-2. Simple HMAC and Policy Code Example

1 void SimpleHmacOrPolicyTest( bool hmacTest ) 2 {

3 UINT32 rval, sessionCmdRval;

4 TPM2B_AUTH nvAuth;

5 SESSION nvSession, trialPolicySession;

6 TPMA_NV nvAttributes;

7 TPM2B_DIGEST authPolicy;

8 TPM2B_NAME nvName;

9 TPM2B_MAX_NV_BUFFER nvWriteData, nvReadData;

10 UINT8 dataToWrite[] = { 0x00, 0xff, 0x55, 0xaa };

11 char sharedSecret[] = "shared secret";

12 int i;

13 TPM2B_ENCRYPTED_SECRET encryptedSalt;

14 TPMT_SYM_DEF symmetric;

15 TPMA_SESSION sessionAttributes;

16 TPM_SE tpmSe;

17 char *testString;

set up authorizations for nV index creation and deletion.

18 // Command authorization area: one password session.

19 TPMS_AUTH_COMMAND nvCmdAuth = { TPM_RS_PW, };

20 TPMS_AUTH_COMMAND *nvCmdAuthArray[1] = { &nvCmdAuth };

21 TSS2_SYS_CMD_AUTHS nvCmdAuths = { 1, &nvCmdAuthArray[0] }; 22

23 // Response authorization area.

24 TPMS_AUTH_RESPONSE nvRspAuth;

25 TPMS_AUTH_RESPONSE *nvRspAuthArray[1] = { &nvRspAuth };

26 TSS2_SYS_RSP_AUTHS nvRspAuths = { 1, &nvRspAuthArray[0] }; 27

28 if( hmacTest )

29 testString = "HMAC";

30 else

31 testString = "POLICY"; 32

33 printf( " SIMPLE %s SESSION TEST: ", testString );

34

35 // Create sysContext structure.

36 sysContext = InitSysContext( 1000, resMgrTctiContext, &abiVersion );

37 if( sysContext == 0 )

38 {

39 InitSysContextFailure(); 40 }

Create the nV index, with either an hMaC or a policy authorization required.

41 // Setup the NV index's authorization value.

42 nvAuth.t.size = strlen( sharedSecret );

43 for( i = 0; i < nvAuth.t.size; i++ )

44 nvAuth.t.buffer[i] = sharedSecret[i]; 45

46 //

47 // Create NV index.

48 //

49 if( hmacTest )

50 {

51 // Set NV index's authorization policy

52 // to zero sized policy since we won't be

53 // using policy to authorize. 54

55 authPolicy.t.size = 0; 56 }

57 else

58 {

59

60 // Zero sized encrypted salt, since the session

61 // is unsalted. 62

63 encryptedSalt.t.size = 0; 64

65 // No symmetric algorithm.

66 symmetric.algorithm = TPM_ALG_NULL; 67

68 //

69 // Create the NV index's authorization policy

70 // using a trial policy session.

71 //

72 rval = StartAuthSessionWithParams( &trialPolicySession,

73 TPM_RH_NULL, TPM_RH_NULL, &encryptedSalt,

74 TPM_SE_TRIAL,

75 &symmetric, TPM_ALG_SHA256 );

76 CheckPassed( rval ); 77

78 rval = Tss2_Sys_PolicyAuthValue( sysContext,

79 trialPolicySession.sessionHandle, 0, 0 );

80 CheckPassed( rval ); 81

82 // Get policy digest.

83 rval = Tss2_Sys_PolicyGetDigest( sysContext,

84 trialPolicySession.sessionHandle,

85 0, &authPolicy, 0 );

86 CheckPassed( rval ); 87

88 // End the trial session by flushing it.

89 rval = Tss2_Sys_FlushContext( sysContext,

90 trialPolicySession.sessionHandle );

91 CheckPassed( rval ); 92

93 // And remove the trial policy session from

94 // sessions table.

95 rval = EndAuthSession( &trialPolicySession );

96 CheckPassed( rval ); 97 }

98

99 // Now set the NV index's attributes:

100 // policyRead, authWrite, and platormCreate.

101 *(UINT32 *)( &nvAttributes ) = 0;

102 if( hmacTest )

103 {

104 nvAttributes.TPMA_NV_AUTHREAD = 1;

105 nvAttributes.TPMA_NV_AUTHWRITE = 1;

106 }

107 else

108 {

109 nvAttributes.TPMA_NV_POLICYREAD = 1;

110 nvAttributes.TPMA_NV_POLICYWRITE = 1;

111 }

112 nvAttributes.TPMA_NV_PLATFORMCREATE = 1; 113

114 // Create the NV index.

115 rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW,

116 &nvAuth, &authPolicy, TPM20_INDEX_PASSWORD_TEST,

117 TPM_ALG_SHA256, nvAttributes, 32 );

118 CheckPassed( rval ); 119

120 // Add index and associated authorization value to

121 // entity table. This helps when we need

122 // to calculate HMACs.

123 AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );

124 CheckPassed( rval );

125

126 // Get the name of the NV index.

127 rval = (*HandleToNameFunctionPtr)(

128 TPM20_INDEX_PASSWORD_TEST,

129 &nvName );

130 CheckPassed( rval );

start the hMaC or policy session.

131 //

132 // Start HMAC or real (non-trial) policy authorization session:

133 // it's an unbound and unsalted session, no symmetric

134 // encryption algorithm, and SHA256 is the session's

135 // hash algorithm.

136 //

137

138 // Zero sized encrypted salt, since the session

139 // is unsalted.

140 encryptedSalt.t.size = 0; 141

142 // No symmetric algorithm.

143 symmetric.algorithm = TPM_ALG_NULL; 144

145 // Create the session, hmac or policy depending

146 // on hmacTest.

147 // Session state (session handle, nonces, etc.) gets

148 // saved into nvSession structure for later use.

149 if( hmacTest )

150 tpmSe = TPM_SE_HMAC;

151 else

152 tpmSe = TPM_SE_POLICY; 153

154 rval = StartAuthSessionWithParams( &nvSession, TPM_RH_NULL,

155 TPM_RH_NULL, &encryptedSalt, tpmSe,

156 &symmetric, TPM_ALG_SHA256 );

157 CheckPassed( rval ); 158

159 // Get the name of the session and save it in

160 // the nvSession structure.

161 rval = (*HandleToNameFunctionPtr)( nvSession.sessionHandle,

162 &nvSession.name );

163 CheckPassed( rval );

do an nV write using either an hMaC or a policy authorization.

164 // Initialize NV write data.

165 nvWriteData.t.size = sizeof( dataToWrite );

166 for( i = 0; i < nvWriteData.t.size; i++ )

167 {

168 nvWriteData.t.buffer[i] = dataToWrite[i];

169 }

170

171 //

172 // Now setup for writing the NV index. 173 //

174 if( !hmacTest )

175 {

176 // Send policy command.

177 rval = Tss2_Sys_PolicyAuthValue( sysContext,

178 nvSession.sessionHandle, 0, 0 );

179 CheckPassed( rval );

180 }

181

182 // First call prepare in order to create cpBuffer.

183 rval = Tss2_Sys_NV_Write_Prepare( sysContext,

184 TPM20_INDEX_PASSWORD_TEST,

185 TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );

186 CheckPassed( rval ); 187

188 // Configure command authorization area, except for HMAC.

189 nvCmdAuths.cmdAuths[0]->sessionHandle =

190 nvSession.sessionHandle;

191 nvCmdAuths.cmdAuths[0]->nonce.t.size = 1;

192 nvCmdAuths.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;

193 *( (UINT8 *)(&sessionAttributes ) ) = 0;

194 nvCmdAuths.cmdAuths[0]->sessionAttributes = sessionAttributes;

195 nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 1; 196

197 // Roll nonces for command

198 RollNonces( &nvSession, &nvCmdAuths.cmdAuths[0]->nonce ); 199

200 // Complete command authorization area, by computing

201 // HMAC and setting it in nvCmdAuths.

202 rval = ComputeCommandHmacs( sysContext,

203 TPM20_INDEX_PASSWORD_TEST,

204 TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,

205 TPM_RC_FAILURE );

206 CheckPassed( rval ); 207

208 // Finally!! Write the data to the NV index.

209 // If the command is successful, the command

210 // HMAC was correct.

211 sessionCmdRval = Tss2_Sys_NV_Write( sysContext,

212 TPM20_INDEX_PASSWORD_TEST,

213 TPM20_INDEX_PASSWORD_TEST,

214 &nvCmdAuths, &nvWriteData, 0, &nvRspAuths );

215 CheckPassed( sessionCmdRval );

Get the response from the nV write. if it's an hMaC session, verify the response hMaC.

216 // Roll nonces for response

217 RollNonces( &nvSession, &nvRspAuths.rspAuths[0]->nonce ); 218

219 if( sessionCmdRval == TPM_RC_SUCCESS )

220 {

221 // If the command was successful, check the

222 // response HMAC to make sure that the

223 // response was received correctly.

224 rval = CheckResponseHMACs( sysContext, sessionCmdRval,

225 &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,

226 TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );

227 CheckPassed( rval );

228 }

229

230 if( !hmacTest )

231 {

232 // Send policy command.

233 rval = Tss2_Sys_PolicyAuthValue( sysContext,

234 nvSession.sessionHandle, 0, 0 );

235 CheckPassed( rval );

236 }

do an nV read, using an hMaC or a policy session. if it's an hMaC session, verify the response hMaC. Finally, test the read data against the write data to make sure they're equal.

237 // First call prepare in order to create cpBuffer.

238 rval = Tss2_Sys_NV_Read_Prepare( sysContext,

239 TPM20_INDEX_PASSWORD_TEST,

240 TPM20_INDEX_PASSWORD_TEST,

241 sizeof( dataToWrite ), 0 );

242 CheckPassed( rval ); 243

244 // Roll nonces for command

245 RollNonces( &nvSession, &nvCmdAuths.cmdAuths[0]->nonce ); 246

247 // End the session after next command.

248 nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 0; 249

250 // Complete command authorization area, by computing

251 // HMAC and setting it in nvCmdAuths.

252 rval = ComputeCommandHmacs( sysContext,

253 TPM20_INDEX_PASSWORD_TEST,

254 TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,

255 TPM_RC_FAILURE );

256 CheckPassed( rval ); 257

258 // And now read the data back.

259 // If the command is successful, the command

260 // HMAC was correct.

261 sessionCmdRval = Tss2_Sys_NV_Read( sysContext,

262 TPM20_INDEX_PASSWORD_TEST,

263 TPM20_INDEX_PASSWORD_TEST,

264 &nvCmdAuths, sizeof( dataToWrite ), 0,

265 &nvReadData, &nvRspAuths );

266 CheckPassed( sessionCmdRval ); 267

268 // Roll nonces for response

269 RollNonces( &nvSession, &nvRspAuths.rspAuths[0]->nonce ); 270

271 if( sessionCmdRval == TPM_RC_SUCCESS )

272 {

273 // If the command was successful, check the

274 // response HMAC to make sure that the

275 // response was received correctly.

276 rval = CheckResponseHMACs( sysContext, sessionCmdRval,

277 &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,

278 TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );

279 CheckPassed( rval );

280 }

281

282 // Check that write and read data are equal.

283 if( memcmp( (void *)&nvReadData.t.buffer[0],

284 (void *)&nvWriteData.t.buffer[0], nvReadData.t.size ) )

285 {

286 printf( "ERROR!! read data not equal to written data " );

287 Cleanup();

288 }

Cleanup: remove the nV index.

289

290

//

291

// Now cleanup: undefine the NV index and delete

292

// the NV index's entity table entry.

293

//

294

295

// Setup authorization for undefining the NV index.

296

nvCmdAuths.cmdAuths[0]->sessionHandle = TPM_RS_PW;

297

nvCmdAuths.cmdAuths[0]->nonce.t.size = 0;

298

nvCmdAuths.cmdAuths[0]->hmac.t.size = 0;

299

300

// Undefine the NV index.

301

rval = Tss2_Sys_NV_UndefineSpace( sysContext,

302

TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST,

303

&nvCmdAuths, 0 );

304

CheckPassed( rval );

305

306

// Delete the NV index's entry in the entity table.

307

rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );

308

CheckPassed( rval );

309

}

I've demonstrated how to send single commands using an HMAC session. Now we need to consider multiple commands and how the nonces work.

 
< Prev   CONTENTS   Next >

Related topics