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