1# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import time
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib.cros import tpm_utils
9from autotest_lib.server import test
10
11# TPM vendor commands have the following header structure:
12
13# 8001      TPM_ST_NO_SESSIONS
14# 00000000  Command/response size
15# 20000000  Cr50 Vendor Command (Constant, TPM Command Code)
16# 0000      Vendor Command Code (VENDOR_CC_ enum)
17
18TPM_TAG_SIZE_BYTES = 2
19VENDOR_CC_SIZE_BYTES = 2
20VENDOR_CMD_HEADER_SIZE_BYTES = 12
21
22# Responses to TPM vendor commands have the following header structure:
23
24# 8001      TPM_ST_NO_SESSIONS
25# 00000000  Response size
26# 00000000  Response code
27# 0000      Vendor Command Code
28
29VENDOR_CMD_RESPONSE_SIZE_OFFSET = TPM_TAG_SIZE_BYTES
30VENDOR_CMD_RESPONSE_SIZE_BYTES = 4
31VENDOR_CMD_RESPONSE_CODE_OFFSET = (
32    VENDOR_CMD_RESPONSE_SIZE_OFFSET + VENDOR_CMD_RESPONSE_SIZE_BYTES)
33VENDOR_CMD_RESPONSE_CODE_SIZE_BYTES = 4
34VENDOR_CMD_RESPONSE_CC_OFFSET = (
35    VENDOR_CMD_RESPONSE_CODE_OFFSET + VENDOR_CMD_RESPONSE_CODE_SIZE_BYTES)
36
37# Vendor command codes being tested
38
39VENDOR_CC_U2F_GENERATE = '002C'
40VENDOR_CC_U2F_SIGN = '002D'
41VENDOR_CC_U2F_ATTEST = '002E'
42
43# Expected response sizes (body only)
44
45VENDOR_CC_U2F_SIGN_RESPONSE_SIZE_BYTES = 64
46VENDOR_CC_U2F_GENERATE_RESPONSE_SIZE_BYTES = 129
47VENDOR_CC_U2F_ATTEST_RESPONSE_SIZE_BYTES = 64
48
49# Response Codes
50
51VENDOR_CMD_RESPONSE_SUCCESS = '00000000'
52VENDOR_CMD_RESPONSE_NOT_ALLOWED = '00000507'
53VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED = '0000050A'
54
55# U2F Attest constants
56
57U2F_ATTEST_FORMAT_REG_RESP = '00'
58U2F_ATTEST_REG_RESP_SIZE_BYTES = 194
59
60# Some 'random' input to simulate actual inputs.
61APP_ID = '699abb209a23ec31dcef298064a92ed9829e70a1bc873b272db321fe1644feae'
62APP_ID_2 = '3c67e46408ec57dc6e4fb46fd0aecddadcf10c7b856446986ef67544a00530fa'
63USER_SECRET_1 = ('1b6e854dcc052dfff2b5ece48c60a9db'
64                 'c69d27315c5f3ef8031abab60aa24d61')
65USER_SECRET_2 = ('26398186431b14de9a6b99f849d71d342'
66                 'a1ec246d413aed42b7f2ac98846f24d')
67HASH_TO_SIGN = ('91f93c8d88ed6168d07a36de53bd62b6'
68                '649e84d343dd417ed6062775739b6e65')
69RANDOM_32 = '0fd2bf886fa8c036d069adf321bf1390859da4d615034c3a81ca3812a210ce0d'
70
71
72def get_bytes(tpm_str, start, length):
73  return tpm_str[(start * 2):(start * 2 + length * 2)]
74
75
76def assert_byte_length(str, len_bytes):
77  """Assert str represents a byte sequence len_bytes long"""
78  assert (len(str) / 2) == len_bytes
79
80
81def get_str_length_as_hex(str, additional_len=0):
82  """Get the length of str plus any additional_len as a hex string."""
83  assert (len(str) % 2) == 0
84  length_bytes = len(str) / 2
85  # hex() returns strings with a '0x' prefix, which we remove.
86  return hex(length_bytes + additional_len)[2:]
87
88
89def check_response_size(response, expected_response, success_size):
90  """If the response is expected to be success, check it's size is as expected,
91
92     otherwise, check it is 0.
93  """
94  response_size = response['length']
95  if expected_response == VENDOR_CMD_RESPONSE_SUCCESS:
96    if response_size != success_size:
97      raise error.TestFail(
98          'Invalid successful response size: {}'.format(response_size))
99  elif response_size != 0:
100    raise error.TestFail(
101        'Non-zero response size on failure: {}'.format(response_size))
102
103
104class firmware_Cr50U2fCommands(test.test):
105  """Tests the custom U2F commands in cr50"""
106
107  version = 1
108
109  def __send_vendor_cmd(self,
110                        vendor_cc,
111                        cmd_body,
112                        expected_response_code=VENDOR_CMD_RESPONSE_SUCCESS):
113    assert_byte_length(vendor_cc, VENDOR_CC_SIZE_BYTES)
114
115    cmd_size_str = get_str_length_as_hex(cmd_body, VENDOR_CMD_HEADER_SIZE_BYTES)
116
117    cmd = (
118        '8001'  # TPM_ST_NO_SESSIONS
119        '{:0>8}'  # Command Size (UINT32)
120        '20000000'  # CR50 Vendor Command (TPM CC)
121        '{}'  # Vendor Command Code (Subcommand Code, UINT16)
122        '{}'  # Command Body
123    ).format(cmd_size_str, vendor_cc, cmd_body)
124
125    result = self.client.run('trunks_send --raw {}'.format(cmd)).stdout.strip()
126
127    if get_bytes(result, 0, TPM_TAG_SIZE_BYTES) != '8001':
128      raise error.TestFail(
129          'Unexpected response tag from vendor command: {}'.format(result))
130
131    response_size_bytes = int(
132        get_bytes(result, VENDOR_CMD_RESPONSE_SIZE_OFFSET,
133                  VENDOR_CMD_RESPONSE_SIZE_BYTES), 16)
134
135    if response_size_bytes < VENDOR_CMD_HEADER_SIZE_BYTES:
136      raise error.TestFail(
137          'Unexpected response length from vendor command: {}'.format(result))
138
139    response_code = get_bytes(result, VENDOR_CMD_RESPONSE_CODE_OFFSET,
140                              VENDOR_CMD_RESPONSE_CODE_SIZE_BYTES)
141
142    if response_code != expected_response_code:
143      raise error.TestFail(
144          'Unexpected response received from vendor command: {}'.format(
145              response_code))
146
147    response_vendor_cc = get_bytes(result, VENDOR_CMD_RESPONSE_CC_OFFSET,
148                                   VENDOR_CC_SIZE_BYTES)
149
150    if response_vendor_cc != vendor_cc:
151      raise error.TestFail(
152          'Received response for unexpected vendor command code: {}'.format(
153              response_vendor_cc))
154
155    response_body_size_bytes = (
156        response_size_bytes - VENDOR_CMD_HEADER_SIZE_BYTES)
157
158    return {
159        'length':
160            response_body_size_bytes,
161        'value':
162            get_bytes(result, VENDOR_CMD_HEADER_SIZE_BYTES,
163                      response_body_size_bytes)
164    }
165
166  def __u2f_sign(self, app_id, user_secret, key_handle, hash, flags,
167                 expected_response):
168    assert_byte_length(app_id, 32)
169    assert_byte_length(user_secret, 32)
170    assert_byte_length(key_handle, 64)
171    assert_byte_length(flags, 1)
172
173    response = self.__send_vendor_cmd(
174        VENDOR_CC_U2F_SIGN, '{}{}{}{}{}'.format(app_id, user_secret, key_handle,
175                                                hash, flags), expected_response)
176
177    expected_response_size = VENDOR_CC_U2F_SIGN_RESPONSE_SIZE_BYTES
178    # 'check-only' requests don't have a response body.
179    if flags == '07':
180      expected_response_size = 0
181
182    check_response_size(response, expected_response, expected_response_size)
183
184  def __u2f_generate(self,
185                     app_id,
186                     user_secret,
187                     flags,
188                     expected_response=VENDOR_CMD_RESPONSE_SUCCESS):
189    assert_byte_length(app_id, 32)
190    assert_byte_length(user_secret, 32)
191    assert_byte_length(flags, 1)
192
193    response = self.__send_vendor_cmd(
194        VENDOR_CC_U2F_GENERATE, '{}{}{}'.format(app_id, user_secret, flags),
195        expected_response)
196
197    check_response_size(response, expected_response,
198                        VENDOR_CC_U2F_GENERATE_RESPONSE_SIZE_BYTES)
199
200    return {
201        'pubKey': response['value'][0:130],
202        'keyHandle': response['value'][130:258]
203    }
204
205  def __u2f_attest(self,
206                   user_secret,
207                   format,
208                   data,
209                   expected_response=VENDOR_CMD_RESPONSE_SUCCESS,
210                   pad=False):
211    assert_byte_length(user_secret, 32)
212    assert_byte_length(format, 1)
213
214    data_len_str = get_str_length_as_hex(data)
215
216    if pad:
217      # Max data size is 256 bytes
218      data = data + '0' * (512 - len(data))
219
220    response = self.__send_vendor_cmd(
221        VENDOR_CC_U2F_ATTEST, '{}{}{}{}'.format(
222            user_secret, format, data_len_str, data), expected_response)
223
224    check_response_size(response, expected_response,
225                        VENDOR_CC_U2F_ATTEST_RESPONSE_SIZE_BYTES)
226
227  def __test_generate_unique(self):
228    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
229    registration_2 = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
230
231    if registration['pubKey'] == registration_2['pubKey']:
232      raise error.TestFail('Public keys not unique')
233
234    if registration['keyHandle'] == registration_2['keyHandle']:
235      raise error.TestFail('Key handles not unique')
236
237  def __test_generate_sign_simple(self):
238    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
239
240    self.servo.power_short_press()
241
242    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
243                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
244
245  def __test_generate_with_presence(self):
246    # Wait 11 seconds to ensure no presence.
247
248    time.sleep(11)
249
250    self.__u2f_generate(
251        APP_ID,
252        USER_SECRET_1,
253        '01',  # U2F_AUTH_FLAG_TUP
254        VENDOR_CMD_RESPONSE_NOT_ALLOWED)
255
256    self.servo.power_short_press()
257
258    self.__u2f_generate(
259        APP_ID,
260        USER_SECRET_1,
261        '01',  # U2F_AUTH_FLAG_TUP
262        VENDOR_CMD_RESPONSE_SUCCESS)
263
264  def __test_generate_consume_presence(self):
265    self.servo.power_short_press()
266
267    self.__u2f_generate(
268        APP_ID,
269        USER_SECRET_1,
270        '03',  # U2F_AUTH_FLAG_TUP | G2F_CONSUME
271        VENDOR_CMD_RESPONSE_SUCCESS)
272
273    self.__u2f_generate(
274        APP_ID,
275        USER_SECRET_1,
276        '01',  # U2F_AUTH_FLAG_TUP
277        VENDOR_CMD_RESPONSE_NOT_ALLOWED)
278
279  def __test_sign_requires_presence(self):
280    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
281
282    # U2F asserts presence by checking for a power button press within the
283    # last 10 seconds, sleep so that we are sure there was not one.
284
285    time.sleep(11)
286
287    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
288                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_NOT_ALLOWED)
289
290  def __test_sign_multiple_no_consume(self):
291    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
292
293    self.servo.power_short_press()
294
295    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
296                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
297
298    # We should be able to sign again, as this will happen within 10
299    # seconds of the power button press, and we did not consume.
300
301    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
302                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
303
304  def __test_sign_consume(self):
305    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
306
307    self.servo.power_short_press()
308
309    self.__u2f_sign(
310        APP_ID,
311        USER_SECRET_1,
312        registration['keyHandle'],
313        HASH_TO_SIGN,
314        '02',  # G2F_CONSUME
315        VENDOR_CMD_RESPONSE_SUCCESS)
316
317    # We should have consumed the power button press, so we should not be
318    # able to sign again.
319
320    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
321                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_NOT_ALLOWED)
322
323  def __test_sign_wrong_user_secret(self):
324    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
325
326    self.servo.power_short_press()
327
328    # Sanity check.
329    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
330                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
331
332    self.__u2f_sign(APP_ID, USER_SECRET_2, registration['keyHandle'],
333                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
334
335  def __test_sign_wrong_app_id(self):
336    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
337
338    self.servo.power_short_press()
339
340    # Sanity check.
341    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
342                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
343
344    self.__u2f_sign(APP_ID_2, USER_SECRET_1, registration['keyHandle'],
345                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
346
347  def __test_sign_invalid_kh(self):
348    self.__u2f_sign(
349        APP_ID,
350        USER_SECRET_1,
351        RANDOM_32 + RANDOM_32,  # KH is 64 bytes long
352        HASH_TO_SIGN,
353        '00',
354        VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
355
356  def __test_sign_check_only(self):
357    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
358
359    # U2F asserts presence by checking for a power button press within the
360    # last 10 seconds, sleep so that we are sure there was not one.
361
362    time.sleep(11)
363
364    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
365                    HASH_TO_SIGN, '07', VENDOR_CMD_RESPONSE_SUCCESS)
366
367  def __test_sign_check_only_with_presence(self):
368    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
369
370    self.servo.power_short_press()
371
372    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
373                    HASH_TO_SIGN, '07', VENDOR_CMD_RESPONSE_SUCCESS)
374
375  def __test_sign_check_only_invalid_kh(self):
376    # U2F asserts presence by checking for a power button press within the
377    # last 10 seconds, sleep so that we are sure there was not one.
378
379    time.sleep(11)
380
381    self.__u2f_sign(APP_ID,
382                    USER_SECRET_1,
383                    RANDOM_32 + RANDOM_32,  # KH is 64 bytes long
384                    HASH_TO_SIGN,
385                    '07',
386                    VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
387
388  def __test_sign_check_only_invalid_kh_with_presence(self):
389    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
390
391    self.servo.power_short_press()
392
393    self.__u2f_sign(APP_ID,
394                    USER_SECRET_1,
395                    RANDOM_32 + RANDOM_32,  # KH is 64 bytes long
396                    HASH_TO_SIGN,
397                    '07',
398                    VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
399
400  def __check_attest_reg_resp(self,
401                              app_id,
402                              key_handle,
403                              user_secret,
404                              expected_response,
405                              pad=False):
406    register_resp = '00{}{}{}{}'.format(
407        app_id,
408        RANDOM_32,  # challenge
409        key_handle,
410        'ff' * 65)  # public key (not verified)
411
412    self.__u2f_attest(user_secret, U2F_ATTEST_FORMAT_REG_RESP, register_resp,
413                      expected_response, pad)
414
415  def __test_attest_simple(self):
416    # Attest does not require user presence
417    time.sleep(11)
418
419    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
420
421    self.__check_attest_reg_resp(APP_ID, registration['keyHandle'],
422                                 USER_SECRET_1, VENDOR_CMD_RESPONSE_SUCCESS)
423
424  def __test_attest_simple_padded(self):
425    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
426
427    self.__check_attest_reg_resp(
428        APP_ID,
429        registration['keyHandle'],
430        USER_SECRET_1,
431        VENDOR_CMD_RESPONSE_SUCCESS,
432        pad=True)
433
434  def __test_attest_wrong_user(self):
435    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
436
437    self.__check_attest_reg_resp(APP_ID, registration['keyHandle'],
438                                 USER_SECRET_2, VENDOR_CMD_RESPONSE_NOT_ALLOWED)
439
440  def __test_attest_wrong_app_id(self):
441    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
442
443    self.__check_attest_reg_resp(APP_ID_2, registration['keyHandle'],
444                                 USER_SECRET_1, VENDOR_CMD_RESPONSE_NOT_ALLOWED)
445
446  def __test_attest_garbage_data(self):
447    self.__u2f_attest(USER_SECRET_1, U2F_ATTEST_FORMAT_REG_RESP,
448                      'ff' * U2F_ATTEST_REG_RESP_SIZE_BYTES,
449                      VENDOR_CMD_RESPONSE_NOT_ALLOWED)
450
451  def __test_attest_invalid_format(self):
452    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
453
454    register_resp = '00{}{}{}{}'.format(
455        APP_ID,
456        RANDOM_32,  # challenge
457        registration['keyHandle'],
458        'ff' * 65)  # public key (not verified)
459
460    # Attempt to attest to valid data with invalid format.
461    self.__u2f_attest(USER_SECRET_1, 'ff', register_resp,
462                      VENDOR_CMD_RESPONSE_NOT_ALLOWED)
463
464  def __test_kh_invalidated_by_powerwash(self):
465    registration = self.__u2f_generate(APP_ID, USER_SECRET_1, '00')
466
467    self.servo.power_short_press()
468
469    # Sanity check
470    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
471                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_SUCCESS)
472
473    # Clear TPM. We should no longer be able to authenticate with the
474    # key handle after this.
475    tpm_utils.ClearTPMOwnerRequest(self.client, wait_for_ready=True)
476
477    self.servo.power_short_press()
478
479    self.__u2f_sign(APP_ID, USER_SECRET_1, registration['keyHandle'],
480                    HASH_TO_SIGN, '00', VENDOR_CMD_RESPONSE_PASSWORD_REQUIRED)
481
482  def run_once(self, host=None):
483    """Run the tests."""
484
485    self.client = host
486    self.servo = host.servo
487    self.servo.initialize_dut()
488
489    # Basic functionality
490    self.__test_generate_unique()
491    self.__test_generate_sign_simple()
492
493    # Generate - presence
494    self.__test_generate_with_presence()
495    self.__test_generate_consume_presence()
496
497    # Sign - presence
498    self.__test_sign_requires_presence()
499    self.__test_sign_multiple_no_consume()
500    self.__test_sign_consume()
501
502    # Sign - key handle
503    self.__test_sign_wrong_user_secret()
504    self.__test_sign_wrong_app_id()
505    self.__test_sign_invalid_kh()
506
507    # Sign - check only
508    self.__test_sign_check_only()
509    self.__test_sign_check_only_with_presence()
510    self.__test_sign_check_only_invalid_kh()
511    self.__test_sign_check_only_invalid_kh_with_presence()
512
513    # Attest
514    self.__test_attest_simple()
515    self.__test_attest_simple_padded()
516    self.__test_attest_wrong_user()
517    self.__test_attest_wrong_app_id()
518    self.__test_attest_garbage_data()
519    self.__test_attest_invalid_format()
520
521    # Powerwash
522    self.__test_kh_invalidated_by_powerwash()
523