-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathek_template.c
More file actions
271 lines (225 loc) · 9.13 KB
/
ek_template.c
File metadata and controls
271 lines (225 loc) · 9.13 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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
* Copyright (C) 2020 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "tpm20linux.h"
#include <tss2/tss2_mu.h>
#define NV_INDEX_RSA_NONCE 0x1c00003
#define NV_INDEX_RSA_TEMPLATE 0x1c00004
#define NV_INDEX_ECC_NONCE 0x1c0000b
#define NV_INDEX_ECC_TEMPLATE 0x1c0000c
#define NV_INDEX_ABSENT 0
#define NV_INDEX_PRESENT 1
// The 'TCG EK Credential Profile' recommends looking for NV indexes using
// TPM2_GetCapabilties. For now, restrict the range to RSA indices.
#define CAPABILITY_HANDLE_START 0x01C00000
#define CAPABILITY_HANDLE_END 0x01C00005
typedef union NvIndexStatus
{
struct {
unsigned int RsaEkCertificate : 1;
unsigned int RsaEkNonce : 1;
unsigned int RsaEkTemplate : 1;
unsigned int EccEkCertificate : 1;
unsigned int EccEkNonce : 1;
unsigned int EccEkTemplate : 1;
};
unsigned int raw;
} NvIndexStatus;
static int GetNVIndices(TSS2_SYS_CONTEXT *sys, TPMS_CAPABILITY_DATA* capability_data)
{
TSS2_RC rval;
TPM2_CAP capability = TPM2_CAP_HANDLES;
TPMI_YES_NO more_data = 0;
rval = Tss2_Sys_GetCapability(sys,
NULL,
capability,
CAPABILITY_HANDLE_START,
(CAPABILITY_HANDLE_END - CAPABILITY_HANDLE_START),
&more_data,
capability_data,
NULL);
if (rval != TSS2_RC_SUCCESS) {
ERROR("Tss2_Sys_GetCapability returned 0x%x", rval);
}
return rval;
}
static NvIndexStatus GetNvIndexStatus(TPMS_CAPABILITY_DATA* capability_data)
{
NvIndexStatus results = {0};
for (int i = 0; i < capability_data->data.handles.count; i++) {
DEBUG("NV index 0x%x is present", capability_data->data.handles.handle[i]);
switch(capability_data->data.handles.handle[i])
{
case NV_IDX_RSA_ENDORSEMENT_CERTIFICATE:
DEBUG("RSA EK Certificate is present at nv index 0x%x", NV_IDX_RSA_ENDORSEMENT_CERTIFICATE)
results.RsaEkCertificate = NV_INDEX_PRESENT;
break;
case NV_INDEX_RSA_NONCE:
DEBUG("RSA nonce is present at nv index 0x%x", NV_INDEX_RSA_NONCE)
results.RsaEkNonce = NV_INDEX_PRESENT;
break;
case NV_INDEX_RSA_TEMPLATE:
DEBUG("RSA template is present at nv index 0x%x", NV_INDEX_RSA_TEMPLATE)
results.RsaEkTemplate = NV_INDEX_PRESENT;
break;
case NV_IDX_ECC_ENDORSEMENT_CERTIFICATE:
DEBUG("ECC EK Certificate is present at nv index 0x%x", NV_IDX_ECC_ENDORSEMENT_CERTIFICATE)
results.EccEkCertificate = NV_INDEX_PRESENT;
break;
case NV_INDEX_ECC_NONCE:
DEBUG("ECC nonce is present at nv index 0x%x", NV_INDEX_ECC_NONCE)
results.EccEkNonce = NV_INDEX_PRESENT;
break;
case NV_INDEX_ECC_TEMPLATE:
DEBUG("ECC template is present at nv index 0x%x", NV_INDEX_ECC_TEMPLATE)
results.EccEkTemplate = NV_INDEX_PRESENT;
break;
default:
DEBUG("Unhandled nv index 0x%x", capability_data->data.handles.handle[i])
break;
}
}
return results;
}
static int UnmarshalEkTemplate(const tpmCtx* ctx, TPM2B_AUTH* ownerAuth, uint32_t nvIndex, TPMT_PUBLIC* outPublic)
{
TSS2_RC rval = -1;
uint8_t* nvBytes;
int nvLength;
DEBUG("Collecting EK template from nv index 0x%x", NV_INDEX_RSA_TEMPLATE);
rval = NvRead(ctx, (uint8_t*)ownerAuth->buffer, ownerAuth->size, TPM2_RH_OWNER, nvIndex, &nvBytes, &nvLength);
if (rval != TPM2_RC_SUCCESS)
{
ERROR("Could not read EK template at index 0x%x. NvRead returned 0x%x", nvIndex, rval);
goto error;
}
rval = Tss2_MU_TPMT_PUBLIC_Unmarshal(nvBytes, nvLength, 0, outPublic);
if (rval != TPM2_RC_SUCCESS)
{
ERROR("Could not unmarshal EK template. Tss2_MU_TPMT_PUBLIC_Unmarshal returned 0x%x", rval);
goto error;
}
rval = TSS2_RC_SUCCESS;
error:
if (nvBytes)
{
free(nvBytes);
}
return rval;
}
static int SetEkNonce(const tpmCtx* ctx, TPM2B_AUTH* ownerAuth, uint32_t nvIndex, TPMT_PUBLIC* outPublic)
{
TSS2_RC rval = -1;
uint8_t* nvBytes;
int nvLength;
rval = NvRead(ctx, (uint8_t*)ownerAuth->buffer, ownerAuth->size, TPM2_RH_OWNER, nvIndex, &nvBytes, &nvLength);
if (rval != TPM2_RC_SUCCESS)
{
ERROR("Could not read EK nonce at index 0x%x. NvRead returned 0x%x", nvIndex, rval);
goto error;
}
memset(&outPublic->unique, 0, sizeof(TPMU_PUBLIC_ID));
memcpy(outPublic->unique.rsa.buffer, nvBytes, nvLength);
outPublic->unique.rsa.size = 256;
rval = TSS2_RC_SUCCESS;
error:
if (nvBytes)
{
free(nvBytes);
}
return rval;
}
// see section 'B.3.3 Template L-1: RSA 2048 (Storage)' in the 'TCG EK Credential Profile' specs
static int SetDefaultRsaTemplate(TPMT_PUBLIC* outPublic)
{
DEBUG("Using default TCG RSA EK template");
memset(outPublic, 0, sizeof(TPMT_PUBLIC));
outPublic->type = TPM2_ALG_RSA;
outPublic->nameAlg = TPM2_ALG_SHA256;
outPublic->objectAttributes |= TPMA_OBJECT_FIXEDTPM;
outPublic->objectAttributes &= ~TPMA_OBJECT_STCLEAR;
outPublic->objectAttributes |= TPMA_OBJECT_FIXEDPARENT;
outPublic->objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
outPublic->objectAttributes &= ~TPMA_OBJECT_USERWITHAUTH;
outPublic->objectAttributes |= TPMA_OBJECT_ADMINWITHPOLICY;
outPublic->objectAttributes &= ~TPMA_OBJECT_NODA;
outPublic->objectAttributes &= ~TPMA_OBJECT_ENCRYPTEDDUPLICATION;
outPublic->objectAttributes |= TPMA_OBJECT_RESTRICTED;
outPublic->objectAttributes |= TPMA_OBJECT_DECRYPT;
outPublic->objectAttributes &= ~TPMA_OBJECT_SIGN_ENCRYPT;
static BYTE auth_policy[] = {
0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, 0x1A, 0x90, 0xCC,
0x8D, 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52,
0x0B, 0x64, 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA
};
outPublic->authPolicy.size = ARRAY_SIZE(auth_policy);
memcpy(outPublic->authPolicy.buffer, auth_policy, ARRAY_SIZE(auth_policy));
outPublic->parameters.rsaDetail.symmetric.algorithm = TPM2_ALG_AES;
outPublic->parameters.rsaDetail.symmetric.keyBits.aes = 128;
outPublic->parameters.rsaDetail.symmetric.mode.aes = TPM2_ALG_CFB;
outPublic->parameters.rsaDetail.scheme.scheme = TPM2_ALG_NULL;
outPublic->parameters.rsaDetail.keyBits = 2048;
outPublic->parameters.rsaDetail.exponent = 0;
outPublic->unique.rsa.size = 256;
}
int GetEkTemplate(const tpmCtx* ctx, TPM2B_AUTH *ownerAuth, TPMT_PUBLIC* outPublic)
{
TSS2_RC rval;
TPMS_CAPABILITY_DATA capability_data = {0};
NvIndexStatus nvIndexStatus;
if (!ctx)
{
ERROR("The TPM context cannot be null");
return -1;
}
if (!outPublic)
{
ERROR("The public structure cannot be null");
return -1;
}
rval = GetNVIndices(ctx->sys, &capability_data);
if (rval != TSS2_RC_SUCCESS) {
return rval;
}
nvIndexStatus = GetNvIndexStatus(&capability_data);
if (nvIndexStatus.RsaEkTemplate == NV_INDEX_PRESENT)
{
LOG("Applying RSA EK template from nv index 0x%x", NV_INDEX_RSA_TEMPLATE);
rval = UnmarshalEkTemplate(ctx, ownerAuth, NV_INDEX_RSA_TEMPLATE, outPublic);
}
else
{
rval = SetDefaultRsaTemplate(outPublic);
}
if (rval != TSS2_RC_SUCCESS) {
return rval;
}
// Populate nonce if present and also check for 'unspecified' scenario...
if (nvIndexStatus.RsaEkNonce == NV_INDEX_PRESENT && nvIndexStatus.RsaEkTemplate == NV_INDEX_PRESENT)
{
LOG("Applying RSA EK nonce from nv index 0x%x", NV_INDEX_RSA_NONCE);
rval = SetEkNonce(ctx, ownerAuth, NV_INDEX_RSA_NONCE, outPublic);
}
else if (nvIndexStatus.RsaEkNonce == NV_INDEX_PRESENT && nvIndexStatus.RsaEkTemplate == NV_INDEX_ABSENT)
{
ERROR("The case of an EK Template Absent and an EK Nonce Populated is unspecified");
return -1;
}
else
{
DEBUG("The EK Nonce will not be applied")
}
DEBUG("Template Type: 0x%x", outPublic->type);
DEBUG("Template Alg: 0x%x", outPublic->nameAlg);
DEBUG("Template Attributes: 0x%x", outPublic->objectAttributes);
DEBUG("Template Auth Size: 0x%x", outPublic->authPolicy.size);
DEBUG("Template Sym Algo: 0x%x", outPublic->parameters.rsaDetail.symmetric.algorithm);
DEBUG("Template Sym Keybits: 0x%x", outPublic->parameters.rsaDetail.symmetric.keyBits);
DEBUG("Template Sym Mode: 0x%x", outPublic->parameters.rsaDetail.symmetric.mode);
DEBUG("Template Scheme: 0x%x", outPublic->parameters.rsaDetail.scheme.scheme);
DEBUG("Template Keybits: 0x%x", outPublic->parameters.rsaDetail.keyBits);
DEBUG("Template Exponent: 0x%x", outPublic->parameters.rsaDetail.exponent);
DEBUG("Template Unique Size: 0x%x", outPublic->unique.rsa.size);
return TSS2_RC_SUCCESS;
}