TPM2.0远程证明仿真

该远程证明仿真试验是对TPM远程证明的一次单机模拟,仅用于熟悉PCA模式下远程证明的流程,与真实远程证明相比省略了很多的流程和细节。

测试环境

  • Ubuntu 20.04.1

  • vmware虚拟TPM2.0

    注:由于使用的PCA模式,并且没有用到TPM2.0的新特性,对于TPM1.2也是可以按照该试验的思路进行模拟

    如何在Vmware虚拟机中安装TPM芯片,参见教程Vmware Fusion TPM安装过程

  • fdupes

    在远程证明部分,隐私CA会使用到的工具。

    在Ubuntu中可以直接通过命令apt install fdupes进行安装

基于TPM2 Tools的远程证明

在实际开始远程证明之前,先介绍两个重要的概——PCR和Quote。

PCR

平台状态寄存器(PCR)是⽤来记录系统运⾏状态的寄存器,TCG规范要求实现的⼀组寄存器,⾄少有 16个(TCG 1.1规范),每个20个字节;TCG 1.2规范中引进了8个额外的平台状态寄存器⽤于实现动态 可信根(DRTM);在TPM 2.0之后,引⼊了多bank的概念。

平台配置寄存器(PCR)是TPM中的存储位置,具有某些唯⼀的属性。可以存储在PCR中的值的⼤⼩取 决于关联的哈希算法⽣成的摘要的⼤⼩。SHA-1 PCR可以存储20个字节– SHA-1摘要的⼤⼩。与同⼀哈希 算法相关的多个PCR被称为PCR库。

read测试

使⽤tpm2_pcrread读取sha1库和sha256库中的0,1,2的值。

reset测试

经过测试无法对前15个PCR寄存器进行置空(reset),但是可以拓展(extend)。PCR 0至15不可复位(属于SRTM,静态可信根)。PCR 16至22主要保留给DRTM或专用于特定位置,并且可能无法重置,具体取决于当前的TPM位置(通常是位置0)。

extend测试

这里选择了PCR寄存器11,12,13进行PCR操作的模拟。

首先创建两个原始数据,两个分别对字符串”CRITICAL-DATA”,进行sha1和sha256计算。

1
2
SHA256_DATA=`echo "CRITICAL-DATA" | openssl dgst -sha256 -binary | xxd -p -c 32`
SHA1_DATA=`echo "CRITICAL-DATA" | openssl dgst -sha1 -binary | xxd -p -c 20`

二者的值如下:

然后对两个数据进行拓展操作,拓展结果放在PCR 11中。

1
2
tpm2_pcrextend 11:sha1=$SHA1_DATA,sha256=$SHA256_DATA
tpm2_pcrread sha1:11+sha256:11

结果如下:

然后使用命令:

1
2
3
INITIAL_SHA1_DATA="0000000000000000000000000000000000000000"
CONCATENATED=`echo -ne $INITIAL_SHA1_DATA; echo $SHA1_DATA`
echo $CONCATENATED
1
echo $CONCATENATED | xxd -r -p | openssl dgst -sha1

同样的方式对sha256进行测试,结果均与PCR中存储的值一致。

Quote

创建EK、AK

创建EK,-c参数代表将创建的密钥上下文对象存储在文件或者句柄中,-G代表使用的密钥算法,-u表示公钥输出,-f代表格式

根据EK创建AK(或者叫AIK)。-C代表密钥层级,-s签名算法,-n代表ak密钥名字。

计算Quote

计算Quote。-l指明计算Quote使用的PCR,-q即防重放攻击的随机数,-m输出的信息(记录被TPM签名的数据的整合信息,该信息可以理解为PCR被Quote处理后的结果),-s签名输出文件,-oPCR记录文件。

Quote的输出信息中最重要的就是-m输出的quote.out-s输出的签名文件。这两个文件会被checkquote进行校验,一旦quote.out中记录的信息出错或者签名文件不正确,均无法通过校验。

type仅有2种TPMS_ATTESTTPMS_CONTEXT数据结构。quote.out文件的内容属于数据结构TPMS_ATTEST

上述输出中还可以看到一个值calcDigest,这是根据PCR的信息计算出来的摘要值,存储在quote.out中的pcrDigest参数中。该值也是远程证明过程中需要校验的重要因素。

TPMS_ATTEST

TPMS_ATTEST结构如下:

  • magic:表明该结构是由TPM创建的,始终为TPM2_GENERATED_VALUE

  • type:证明结构的类型。对于具有PCR信息的类型为TPM2_ST_ATTEST_QUOTE,在此进行详细讨论。

  • qualifiedSigner:签名密钥的合格名称。术语合格名称是所有祖先键的所有名称的摘要,这些名称返回到层次结构根部的“主种子”。

  • extraData:调用方提供的外部信息。由“服务提供商”生成的NONCE添加在此字段中。

  • clock:TPM通电的时间(以毫秒为单位)。更改“存储主种子” TPM2_Clear时,此值重置为零。

  • resetCount:自上一次TPM2_Clear以来发生的TPM重置次数。

  • restartCount:自上一次TPM重置或TPM2_Clear以来发生TPM2_Shutdown_TPM_Hash_Start的次数。

  • safe:指示TPM先前未报告过Clock的值大于Clock的当前值。在TPM2_Clear上设置为YES。

  • firmwareVersion:TPM供应商特定的值,用于标识固件的版本号。

  • pcrSelect:有关algID(使用的签名算法),选择的PCR和摘要的信息。

  • count:选择结构的数量。允许值为零。这表示所选PCR库的数量(SHA1,SHA256等)

  • pcrSelections:这是PCR选择结构的列表。

    1. hash:与选择库关联的哈希算法。

    2. sizeofSelectpcrSelect数组的字节大小。这表示代表库中所有PCR所需的字节数。每个PCR都以位表示。例如,对于每个存储库24个PCR,selectof的大小应为3个字节。

    3. pcrSelect:所选PCR的位图(最低有效字节在前)。位图结构如下,选择了15,16和22号PCR。

  • pcrDigest:使用签名密钥的哈希算法选择的PCR的摘要。

TPMS_CONTEXT

该类型是密钥上下文(key context)的数据结构。上文中创建的EK.ctx和AK.ctx均属于这个类型。

CheckQuote

最后校验Quote信息。通过Quote提供的签名,TPM记录,pcrs的记录,随机数,以及ak公钥验证。分别使用错误的随机数,以及错误的签名信息,结果如下。

使用tpm2-tools进行简单证明

该远程证明由于是单机实现,因此采用一个文件夹来模拟一个设备,不同文件夹之间拷贝数据来模拟设备间的通信。

证明模型中的目标和角色

  1. 设备节点 Device-Node:具有TPM的边缘平台,其系统软件状态受关注。 它使用Quote中包含的PCR数据摘要生成证明结构。平台使用用于匿名的证明身份密钥(AIK)对Quote进行签名。AIK以密码方式绑定到同一平台上的唯一身份密钥。唯一的身份密钥是背书密钥(EK)。

  2. 隐私CA Privacy-CA:唯一一个可以证明AIK与有效EK关联而无需将EK暴露给“服务供应商”的可信实体。 这也是除“设备节点”之外唯一从“设备节点”给定AIK了解EK的实体。

  3. 服务供应商 Service-Provider:与“设备节点”通信以使用服务的实体。“服务供应商”需要确保以下几点:

    a. 实体请求服务已在“ Privacy-CA”中注册了其唯一身份。

    b. 匿名身份属于“ Privacy-CA”存储的已注册唯一身份池。

    c. “设备节点”的系统软件状态是可以接受的状态。

远程证明中的初始状态

我们共有三台设备,分别是一个设备节点(DNODE),一个服务供应商(SP),以及一个隐私CA(PCA)。如下图:

对于DNODE,它初始时仅知道SP的位置以及自己的位置,对于PCA的位置是未知的。

对于SP,它初始时仅知道PCA的位置,而对于设备节点的位置是未知的。

但是在SP的数据库是事先存有DNODE的要证实的PCR列表以及对应摘要信息的。

对于PCA,它也仅知道SP的位置,对于设备节点的位置是未知的,同样初始时token是不存在。

Step 1 - 注册

部分关键代码解释:

  1. 设备注册过程创建ek和aik

  2. 隐私CA获取ek公钥,aik公钥和aik的名字

  3. 隐私CA创建公钥证书并在证书中包含一个秘密,发送给设备节点

  4. 设备节点解密之后将结果发回给隐私CA

  5. 隐私CA收到后,判断设备节点解析的秘密是否匹配

步骤3、4、5是隐私CA校验设备节点的身份。

Step 2 - 平台匿名身份验证

这一步的过程与注册类似。设备将AIK公钥发送给服务供应商。服务供应商将AIK公钥发送给隐私CA以验证设备节点的身份。然后隐私CA请求设备的EK公钥以验证设备的身份。

Step 3 - 平台状态验证

部分关键代码解释:

  1. 上一步TOKEN校验通过之后,服务供应商向设备发送一个PCR清单和一个随机数NONCE。

  2. 设备收到PCR清单和随机数之后,对这些信息进行Quote计算。Quote会生成四份信息,TPMS_ATTEST结构信息的文件attestation_quote.dat、一个签名文件attestation_quote.signature、PCR内容信息文件pcr.bin,以及一个PCR摘要calcdigest(其包含在TPMS_ATTEST结构中)。然后将生成好的TPMS_ATTEST文件和签名文件发送给服务供应商。

  3. 服务供应商收到Quote信息后,首先使用之前收到的AIK公钥对其进行校验,校验会同时检验签名文件和随机数是否正确

  4. 服务供应商接着从TPMS_ATTEST中提取PCR的摘要与自身保存的摘要信息进行匹配。至此远程证实工作完成。

device_node代码

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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
#!/bin/bash


# Fixed location
service_provider_location="$PWD/../SP"

# PCA location
privacy_ca_location=""

# Location for node 1, node 2, etc.
device_location="$PWD"

# State
event_file_found=0
device_registration_request=0
device_service_request=0

wait_loop() {
counter=1
until [ $counter -gt $1 ]
do
test -f $2
if [ $? == 0 ];then
event_file_found=1
break
else
echo -ne "Waiting $1 seconds: $counter"'\r'
fi
((counter++))
sleep 1
done
}

LOG_ERROR() {
errorstring=$1
echo -e "\033[31mFAIL: \e[97m${errorstring}\e[0m"
}

LOG_INFO() {
messagestring=$1
echo -e "\033[93mPASS: \e[97m${messagestring}\e[0m"
}

await_and_compelete_credential_challenge() {

# Wait for credential challenge
cred_status_string="Encrypted credential receipt from Privacy-CA."
max_wait=60
wait_loop $max_wait cred.out
if [ $event_file_found == 0 ];then
LOG_ERROR "$cred_status_string"
return 1
fi
event_file_found=0
LOG_INFO "$cred_status_string"

tpm2_startauthsession --policy-session --session session.ctx -Q

TPM2_RH_ENDORSEMENT=0x4000000B
tpm2_policysecret -S session.ctx -c $TPM2_RH_ENDORSEMENT -Q

tpm2_activatecredential --credentialedkey-context rsa_ak.ctx \
--credentialkey-context rsa_ek.ctx --credential-blob cred.out \
--certinfo-data actcred.out --credentialkey-auth "session:session.ctx" -Q

rm -f cred.out

tpm2_flushcontext session.ctx -Q

rm -f session.ctx
}

device_registration() {

# Send device location to service-provider
echo "device_location: $device_location" > d_s_registration.txt
cp d_s_registration.txt $service_provider_location/.
rm -f d_s_registration.txt

# Wait for PCA location information from service provider
max_wait=60
wait_loop $max_wait s_d_registration.txt
registration_status_string="Privacy-CA information receipt from Service-Provider."
if [ $event_file_found == 0 ];then
LOG_ERROR "$registration_status_string"
return 1
fi
event_file_found=0
LOG_INFO "$registration_status_string"
privacy_ca_location=`grep privacy_ca_location s_d_registration.txt | \
awk '{print $2}'`
rm -f s_d_registration.txt

registration_status_string="Acknowledgement reciept from Privacy-CA."
wait_loop $max_wait p_d_pca_ready.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$registration_status_string"
return 1
fi
event_file_found=0
LOG_INFO "$registration_status_string"
rm -f p_d_pca_ready.txt

#Ready EKcertificate, EK and AIK and set ready status so PCA can pull
tpm2_createek --ek-context rsa_ek.ctx --key-algorithm rsa \
--public rsa_ek.pub -Q

tpm2_startauthsession -S session.ctx --policy-session -Q
tpm2_policysecret -S session.ctx -c e -Q
tpm2_create -C rsa_ek.ctx -u rsa_ak.pub -r rsa_ak.priv \
-P session:session.ctx -Q
tpm2_policysecret -S session.ctx -c e -Q
tpm2_load -C rsa_ek.ctx -P session:session.ctx -u rsa_ak.pub -r rsa_ak.priv -c rsa_ak.ctx -Q
tpm2_readpublic -c rsa_ak.ctx -f pem -o rsa_ak.pub -n rsa_ak.name -Q
tpm2_flushcontext session.ctx -Q

touch fake_ek_certificate.txt

touch d_p_device_ready.txt
cp d_p_device_ready.txt $privacy_ca_location/.
rm -f d_p_device_ready.txt

registration_status_string="Credential activation challenge."
await_and_compelete_credential_challenge
if [ $? == 0 ];then
LOG_INFO "$registration_status_string"
cp actcred.out $privacy_ca_location/.
rm -f actcred.out
return 0
else
LOG_ERROR "$registration_status_string"
return 1
fi
}

request_device_registration () {

device_registration
if [ $? == 1 ];then
return 1
fi

device_registration_status_string="Registration token receipt from Privacy-CA."
max_wait=60
wait_loop $max_wait p_d_registration_token.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$device_registration_status_string"
return 1
fi
LOG_INFO "$device_registration_status_string"
event_file_found=0
cp p_d_registration_token.txt \
$service_provider_location/d_s_registration_token.txt
rm -f p_d_registration_token.txt

return 0
}

#
# Request service with the Service-Provider
# Read the Privacy-CA location from Service-Provider
# Deliver EK, AIK, EKcertificate to the Privacy-CA
# Complete credential challenge with the Privacy-CA
# Retrieve the SERVICE-TOKEN from the Privacy-CA
# Present the SEVICE-TOKEN to the Service-Provider
#
process_device_anonymous_identity_challenge() {

# Start device service
test -f $device_service_aik
if [ $? == 1 ];then
LOG_ERROR "Aborting service request - AIK could not be found."
return 1
else
echo "device_location: $device_location" > d_s_service.txt
cp d_s_service.txt $service_provider_location/.
rm -f d_s_service.txt
cp $device_service_aik $service_provider_location/d_s_service_aik.pub
fi

identity_challenge_status_string="Privacy-CA information receipt from Service-Provider."
max_wait=60
wait_loop $max_wait s_d_service.txt
if [ $event_file_found == 1 ];then
event_file_found=0
privacy_ca_location=`grep privacy_ca_location s_d_service.txt | \
awk '{print $2}'`
rm -f s_d_service.txt
LOG_INFO "$identity_challenge_status_string"
else
LOG_ERROR "$identity_challenge_status_string"
return 1
fi

identity_challenge_status_string="Acknowledgement receipt from Privacy-CA."
wait_loop $max_wait p_d_pca_ready.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$identity_challenge_status_string"
return 1
fi

LOG_INFO "$identity_challenge_status_string"
event_file_found=0
rm -f p_d_pca_ready.txt

touch d_p_device_ready.txt
cp d_p_device_ready.txt $privacy_ca_location/.
rm -f d_p_device_ready.txt

identity_challenge_status_string="Credential activation challenge."
await_and_compelete_credential_challenge
if [ $? == 0 ];then
LOG_INFO "$identity_challenge_status_string"
cp actcred.out $privacy_ca_location/.
rm -f actcred.out
else
LOG_ERROR "$identity_challenge_status_string"
rm -f actcred.out
return 1
fi

identity_challenge_status_string="Service-Token receipt from Privacy-CA."
wait_loop $max_wait p_d_service_token.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$identity_challenge_status_string"
return 1
fi
LOG_INFO "$identity_challenge_status_string"
event_file_found=0
cp p_d_service_token.txt \
$service_provider_location/d_s_service_token.txt
rm -f p_d_service_token.txt

return 0
}

process_device_software_state_validation_request() {

software_state_string="PCR selection list receipt from Service-Provider"
max_wait=60
wait_loop $max_wait s_d_pcrlist.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$software_state_string"
return 1
fi
LOG_INFO "$software_state_string"
event_file_found=0
pcr_selection=`grep pcr-selection s_d_pcrlist.txt | \
awk '{print $2}'`
service_provider_nonce=`grep nonce s_d_pcrlist.txt | \
awk '{print $2}'`
rm -f s_d_pcrlist.txt

tpm2_quote --key-context rsa_ak.ctx --message attestation_quote.dat \
--signature attestation_quote.signature \
--qualification "$service_provider_nonce" \
--pcr-list "$pcr_selection" \
--pcr pcr.bin -Q

cp attestation_quote.dat attestation_quote.signature pcr.bin \
$service_provider_location/.

return 0
}

process_encrypted_service_data_content() {

service_data_status_string="Encrypted service-data-content receipt from Service-Provider"
max_wait=6
wait_loop $max_wait s_d_service_content.encrypted
if [ $event_file_found == 0 ];then
LOG_ERROR "$service_data_status_string"
return 1
fi
LOG_INFO "$service_data_status_string"
event_file_found=0

service_data_status_string="Decryption of service-data-content receipt from Service-Provider"
tpm2_rsadecrypt -c rsa_ak.ctx -o s_d_service_content.decrypted \
s_d_service_content.encrypted -Q
if [ $? == 1 ];then
LOG_ERROR "$service_data_status_string"
rm -f s_d_service_content.encrypted
return 1
fi
LOG_INFO "$service_data_status_string"

SERVICE_CONTENT=`cat s_d_service_content.decrypted`
LOG_INFO "Service-content: \e[5m$SERVICE_CONTENT"
rm -f s_d_service_content.*

return 0
}

request_device_service() {

request_service_status_string="Device anonymous identity challenge."
process_device_anonymous_identity_challenge
if [ $? == 1 ];then
LOG_ERROR "$request_service_status_string"
return 1
fi
LOG_INFO "$request_service_status_string"

request_service_status_string="Device software state validation"
process_device_software_state_validation_request
if [ $? == 1 ];then
LOG_ERROR "$request_service_status_string"
return 1
fi
LOG_INFO "$request_service_status_string"

request_service_status_string="Service data content processing"
process_encrypted_service_data_content
if [ $? == 1 ];then
LOG_ERROR "$request_service_status_string"
return 1
fi

return 0
}

tput sc
read -r -p "Demonstration purpose only, not for production. Continue? [y/N] " response
tput rc
tput el
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo "===================== DEVICE-NODE ====================="
else
exit
fi


while getopts ":hrt:" opt; do
case ${opt} in
h )
echo "Pass 'r' for registration or 't' for service request"
;;
r )
device_registration_request=1
;;
t )
device_service_request=1
device_service_aik=$OPTARG
;;
esac
done
shift $(( OPTIND - 1 ))

if [ $device_registration_request == 1 ];then
if [ $device_service_request == 1 ];then
echo "Specify either 'registration' or 'service' request not both"
exit 1
fi
fi

status_string="Device registration request."
if [ $device_registration_request == 1 ];then
request_device_registration
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
LOG_INFO "$status_string"
fi

status_string="Device service request."
if [ $device_service_request == 1 ];then
request_device_service
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
fi

if [ $device_registration_request == 0 ];then
if [ $device_service_request == 0 ];then
echo "Usage: device-node.sh [-h] [-r] [-t AIK.pub]"
exit 1
fi
fi

# No errors
exit 0

private_ca代码

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
#!/bin/bash

# Fixed location
service_provider_location="$PWD/../SP"

# Location for node 1, node 2, etc.
device_location=""
registration_token=""

# State
event_file_found=0

wait_loop() {
counter=1
until [ $counter -gt $1 ]
do
test -f $2
if [ $? == 0 ];then
event_file_found=1
break
else
echo -ne "Waiting $1 seconds: $counter"'\r'
fi
((counter++))
sleep 1
done
}

LOG_ERROR() {
errorstring=$1
echo -e "\033[31mFAIL: \e[97m${errorstring}\e[0m"
}

LOG_INFO() {
messagestring=$1
echo -e "\033[93mPASS: \e[97m${messagestring}\e[0m"
}

process_device_registration_request_from_service_provider() {

device_location=`grep device_location s_p_registration.txt | \
awk '{print $2}'`
registration_token=`grep registration_token s_p_registration.txt | \
awk '{print $2}'`
rm -f s_p_registration.txt

return 0
}

credential_challenge() {

file_size=`stat --printf="%s" rsa_ak.name`
loaded_key_name=`cat rsa_ak.name | xxd -p -c $file_size`

echo "this is my secret" > file_input.data
tpm2_makecredential --tcti none --encryption-key rsa_ek.pub \
--secret file_input.data --name $loaded_key_name \
--credential-blob cred.out

cp cred.out $device_location/.

credential_status_string="Activated credential receipt from device."
max_wait=60
wait_loop $max_wait actcred.out
if [ $event_file_found == 0 ];then
LOG_ERROR "$credential_status_string"
return 1
fi
LOG_INFO "$credential_status_string"
event_file_found=0

diff file_input.data actcred.out
test=$?
rm -f rsa_ak.* file_input.data actcred.out cred.out
credential_status_string="Credential activation challenge."
if [ $test == 0 ];then
LOG_INFO "$credential_status_string"
return 0
else
LOG_ERROR "$credential_status_string"
return 1
fi
}

process_device_registration_processing_with_device() {

touch p_d_pca_ready.txt
cp p_d_pca_ready.txt $device_location/.
rm -f p_d_pca_ready.txt

process_registration_status_string="Device-ready acknowledgement receipt from device."
max_wait=60
wait_loop $max_wait d_p_device_ready.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$process_registration_status_string"
return 1
fi
LOG_INFO "$process_registration_status_string"
event_file_found=0
rm -f d_p_device_ready.txt

cp $device_location/rsa_ek.pub .
cp $device_location/rsa_ak.pub .
cp $device_location/rsa_ak.name .
LOG_INFO "Received EKcertificate EK and AIK from device"

credential_challenge
if [ $? == 1 ];then
return 1
fi

return 0
}

request_device_registration() {

mkdir -p Registered_EK_Pool

registration_request_status_string="Device info and registration-token receipt from service-provider."
process_device_registration_request_from_service_provider
if [ $? == 1 ];then
LOG_ERROR "$registration_request_status_string"
return 1
fi
LOG_INFO "$registration_request_status_string"

registration_request_status_string="Registration-token dispatch to device."
process_device_registration_processing_with_device
if [ $? == 1 ];then
LOG_ERROR "$registration_request_status_string"
return 1
else
LOG_INFO "$registration_request_status_string"
echo "registration_token: $registration_token" > \
p_d_registration_token.txt
cp p_d_registration_token.txt $device_location/.
rm -f p_d_registration_token.txt
fi

mv rsa_ek.pub Registered_EK_Pool/$registration_token
fdupes --recurse --omitfirst --noprompt --delete --quiet \
Registered_EK_Pool | grep -q rsa_ek.pub

return 0
}

request_device_service() {

device_location=`grep device_location s_p_service.txt | \
awk '{print $2}'`
service_token=`grep service_token s_p_service.txt | \
awk '{print $2}'`
rm -f s_p_service.txt

cp s_p_service_aik.pub $device_location/rsa_ak.pub
rm -f s_p_service_aik.pub
process_device_registration_processing_with_device
if [ $? == 1 ];then
LOG_ERROR "AIK received from service provider is not on the device"
return 1
fi

cp rsa_ek.pub Registered_EK_Pool
fdupes --recurse --omitfirst --noprompt --delete --quiet \
Registered_EK_Pool | grep -q rsa_ek.pub
retval=$?
rm -f rsa_ek.pub Registered_EK_Pool/rsa_ek.pub
if [ $retval == 1 ];then
LOG_ERROR "EK from device does not belong to the registered EK pool"
return 1
fi

echo "service-token: $service_token" > p_d_service_token.txt
cp p_d_service_token.txt $device_location
rm -f p_d_service_token.txt

return 0
}

tput sc
read -r -p "Demonstration purpose only, not for production. Continue? [y/N] " response
tput rc
tput el
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo "===================== PRIVACY-CA ====================="
else
exit
fi


device_registration_request=0
device_service_request=0
counter=1
max_wait=60
until [ $counter -gt $max_wait ]
do
! test -f s_p_registration.txt
device_registration_request=$?
! test -f s_p_service.txt
device_service_request=$?

if [ $device_registration_request == 1 ];then
status_string="Device registration request."
request_device_registration
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
LOG_INFO "$status_string"
break
elif [ $device_service_request == 1 ];then
status_string="Device service request received."
request_device_service
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
LOG_INFO "$status_string"
break
else
echo -ne "Waiting $1 seconds: $counter"'\r'
fi
((counter++))
sleep 1
done

if [ $device_registration_request == 0 ];then
if [ $device_service_request == 0 ];then
LOG_ERROR "Exiting as there are no service provider requests to process."
exit 1
fi
fi

# No errors
exit 0

service_provider代码

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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#!/bin/bash

# Fixed location
pca_location="$PWD/../PCA"

# Device Location not fixed
device_location=""

# State
event_file_found=0
device_registration_request=0
device_service_request=0

# Attestation Data
GOLDEN_PCR_SELECTION="sha1:0,1,2+sha256:0,1,2"
GOLDEN_PCR="3287d55f2eb854d7f653f359efc1e21aa1ac3ed5ea9a4a553e2f54fdd94b1586"

# Service Data
SERVICE_CONTENT="Hello world!"

wait_loop() {
counter=1
until [ $counter -gt $1 ]
do
test -f $2
if [ $? == 0 ];then
event_file_found=1
break
else
echo -ne "Waiting $1 seconds: $counter"'\r'
fi
((counter++))
sleep 1
done
}

LOG_ERROR() {
errorstring=$1
echo -e "\033[31mFAIL: \e[97m${errorstring}\e[0m"
}

LOG_INFO() {
messagestring=$1
echo -e "\033[93mPASS: \e[97m${messagestring}\e[0m"
}

device_registration() {

REGISTRATION_TOKEN=`dd if=/dev/urandom bs=1 count=32 status=none | \
xxd -p -c32`

device_location=`grep device_location d_s_registration.txt | \
awk '{print $2}'`
rm -f d_s_registration.txt

data_to_privacy_ca="
device_location: $device_location
registration_token: $REGISTRATION_TOKEN
"

echo "$data_to_privacy_ca" > s_p_registration.txt
cp s_p_registration.txt $pca_location/.
rm -f s_p_registration.txt

# Send privacy-CA information to device
echo "privacy_ca_location: $pca_location" > s_d_registration.txt
cp s_d_registration.txt $device_location/.
rm -f s_d_registration.txt

# Wait for device_registration_token from device
registration_status_string="Registration-Token reciept from device."
wait_loop $max_wait d_s_registration_token.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$registration_status_string"
return 1
fi
LOG_INFO "$registration_status_string"
event_file_found=0
test_registration_token=`grep registration_token \
d_s_registration_token.txt | awk '{print $2}'`
rm -f d_s_registration_token.txt

registration_status_string="Registration-Token validation"
if [ $test_registration_token == $REGISTRATION_TOKEN ];then
LOG_INFO "$registration_status_string"
return 0
else
LOG_ERROR "$registration_status_string"
return 1
fi
}

device_node_identity_challenge() {
SERVICE_TOKEN=`dd if=/dev/urandom bs=1 count=32 status=none | \
xxd -p -c32`

device_location=`grep device_location d_s_service.txt | \
awk '{print $2}'`
rm -f d_s_service.txt

data_to_privacy_ca="
device_location: $device_location
service_token: $SERVICE_TOKEN
"

echo "$data_to_privacy_ca" > s_p_service.txt
cp s_p_service.txt $pca_location/.
rm -f s_p_service.txt

# Send privacy-CA information to device
echo "privacy_ca_location: $pca_location" > s_d_service.txt
cp s_d_service.txt $device_location
rm -f s_d_service.txt

identity_challenge_status_string="Aborting service request - AIK not found."
test -f d_s_service_aik.pub
if [ $? == 1 ];then
LOG_ERROR "$identity_challenge_status_string"
return 1
else
cp d_s_service_aik.pub $pca_location/s_p_service_aik.pub
fi

identity_challenge_status_string="Service-Token receipt from device."
wait_loop $max_wait d_s_service_token.txt
if [ $event_file_found == 0 ];then
LOG_ERROR "$identity_challenge_status_string"
return 1
fi
LOG_INFO "$identity_challenge_status_string"
event_file_found=0
test_service_token=`grep service-token \
d_s_service_token.txt | awk '{print $2}'`
rm -f d_s_service_token.txt

identity_challenge_status_string="Service-Token validation."
if [ $test_service_token == $SERVICE_TOKEN ];then
LOG_INFO "$identity_challenge_status_string"
return 0
fi
LOG_ERROR "$identity_challenge_status_string"

return 1
}

system_software_state_validation() {

rm -f attestation_quote.dat attestation_quote.signature
echo "pcr-selection: $GOLDEN_PCR_SELECTION" > s_d_pcrlist.txt
NONCE=`dd if=/dev/urandom bs=1 count=32 status=none | xxd -p -c32`
echo "nonce: $NONCE" >> s_d_pcrlist.txt
cp s_d_pcrlist.txt $device_location/.
rm -f s_d_pcrlist.txt

software_status_string="Attestation data receipt from device"
max_wait=60
wait_loop $max_wait attestation_quote.dat
if [ $event_file_found == 0 ];then
LOG_ERROR "$software_status_string"
return 1
fi
LOG_INFO "$software_status_string"
event_file_found=0

software_status_string="Attestation signature receipt from device"
max_wait=60
wait_loop $max_wait attestation_quote.signature
if [ $event_file_found == 0 ];then
LOG_ERROR "$software_status_string"
return 1
fi
LOG_INFO "$software_status_string"
event_file_found=0

software_status_string="Attestation quote signature validation"
tpm2_checkquote --public d_s_service_aik.pub --qualification "$NONCE" \
--message attestation_quote.dat --signature attestation_quote.signature \
--pcr pcr.bin -Q
retval=$?
rm -f attestation_quote.signature
if [ $retval == 1 ];then
LOG_ERROR "$software_status_string"
return 1
fi
LOG_INFO "$software_status_string"

software_status_string="Verification of PCR from quote against golden reference"
testpcr=`tpm2_print -t TPMS_ATTEST attestation_quote.dat | \
grep pcrDigest | awk '{print $2}'`
rm -f attestation_quote.dat
if [ "$testpcr" == "$GOLDEN_PCR" ];then
LOG_INFO "$software_status_string"
else
LOG_ERROR "$software_status_string"
echo -e " \e[97mDevice-PCR: $testpcr\e[0m"
echo -e " \e[97mGolden-PCR: $GOLDEN_PCR\e[0m"
return 1
fi

return 0
}

request_device_service() {
# Start device service registration with device identity challenge
request_device_service_status_string="Anonymous identity validation by Privacy-CA."
device_node_identity_challenge
if [ $? == 1 ];then
LOG_ERROR "$request_device_service_status_string"
rm -f d_s_service_aik.pub
return 1
fi
LOG_INFO "$request_device_service_status_string"

# Check the device software state by getting a device quote
request_device_service_status_string="Device system software validation."
system_software_state_validation
if [ $? == 1 ];then
LOG_ERROR "$request_device_service_status_string"
rm -f d_s_service_aik.pub
return 1
fi
LOG_INFO "$request_device_service_status_string"

# Encrypt service data content and deliver
echo "$SERVICE_CONTENT" > service-content.plain
openssl rsautl -encrypt -inkey d_s_service_aik.pub -pubin \
-in service-content.plain -out s_d_service_content.encrypted

cp s_d_service_content.encrypted $device_location/.
rm -f d_s_service_aik.pub
rm -f s_d_service_content.encrypted
rm -f service-content.plain
LOG_INFO "Sending service-content: \e[5m$SERVICE_CONTENT"

return 0
}

tput sc
read -r -p "Demonstration purpose only, not for production. Continue? [y/N] " response
tput rc
tput el
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo "===================== SERVICE-PROVIDER ====================="
else
exit
fi

counter=1
max_wait=60
until [ $counter -gt $max_wait ]
do
! test -f d_s_registration.txt
device_registration_request=$?
! test -f d_s_service.txt
device_service_request=$?

status_string="Device registration request."
if [ $device_registration_request == 1 ];then
device_registration
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
LOG_INFO "$status_string"
break
elif [ $device_service_request == 1 ];then
status_string="Device service request."
request_device_service
if [ $? == 1 ];then
LOG_ERROR "$status_string"
exit 1
fi
LOG_INFO "$status_string"
break
else
echo -ne "Waiting $1 seconds: $counter"'\r'
fi
((counter++))
sleep 1
done

if [ $device_registration_request == 0 ];then
if [ $device_service_request == 0 ];then
LOG_ERROR "Exiting as there are no device requests to process"
exit 1
fi
fi

# No errors
exit 0

参考资料

  1. UEFI启动和Bios(Legacy)启动的区别. https://blog.csdn.net/zhangxiangweide/article/details/95342334
  2. TPM 1.2与2.0的特点. https://www.dell.com/support/kbdoc/zh-cn/000131631/tpm-1-2%E4%B8%8E2-0%E7%9A%84%E7%89%B9%E7%82%B9
  3. BIOS工作原理. https://blog.csdn.net/maomaovv/article/details/1549819
  4. https://docs.microsoft.com/en-us/windows/security/information-protection/tpm/switch-pcr-banks-on-tpm-2-0-devices
  5. https://github.com/tpm2-software/tpm2-tools/issues/1884
  6. https://github.com/tpm2-software/tpm2-tools/issues/2181
  7. https://zhuanlan.zhihu.com/p/33858479
  8. https://www.mvndoc.com/c/com.github.microsoft/TSS.Java/tss/tpm/TPMS_CONTEXT.html
  9. https://www.cnblogs.com/embedded-linux/p/6716740.html
  10. https://tpm2-software.github.io/2020/06/12/Remote-Attestation-With-tpm2-tools.html#tools-and-utilities-used-from-the-tpm2-tools-project
  11. https://lxr.missinglinkelectronics.com/uboot/include/tpm-v2.h
Author

Chaos Chen

Posted on

2021-01-03

Updated on

2023-06-30

Licensed under

Commentaires