2019-09-16 16:26:47 +08:00
import sys
2019-08-05 13:40:54 +08:00
import pytest
from fido2.ctap import CtapError
2019-08-13 22:40:20 +02:00
from fido2.utils import hmac_sha256 , sha256
2019-08-05 13:40:54 +08:00
from tests.utils import *
class TestGetAssertion ( object ):
2019-08-08 03:05:15 +02:00
def test_get_assertion ( self , device , MCRes , GARes ):
2019-08-05 13:40:54 +08:00
verify ( MCRes , GARes )
2019-08-08 03:05:15 +02:00
def test_assertion_auth_data ( self , GARes ):
2019-08-05 13:40:54 +08:00
assert len ( GARes . auth_data ) == 37
assert sha256 ( GARes . request . rp [ "id" ] . encode ()) == GARes . auth_data . rp_id_hash
def test_Check_that_AT_flag_is_not_set ( self , GARes ):
assert ( GARes . auth_data . flags & 0xF8 ) == 0
2019-08-08 03:05:15 +02:00
def test_that_user_credential_and_numberOfCredentials_are_not_present ( self , GARes ):
2019-08-05 13:40:54 +08:00
assert GARes . user == None
assert GARes . number_of_credentials == None
2019-08-08 03:05:15 +02:00
def test_empty_allowList ( self , device ):
2019-08-05 13:40:54 +08:00
with pytest . raises ( CtapError ) as e :
2019-08-08 03:05:15 +02:00
device . sendGA ( * FidoRequest ( allow_list = []) . toGA ())
2019-08-05 13:40:54 +08:00
assert e . value . code == CtapError . ERR . NO_CREDENTIALS
2019-08-08 03:05:15 +02:00
def test_corrupt_credId ( self , device , MCRes ):
2019-08-05 13:40:54 +08:00
# apply bit flip
badid = list ( MCRes . auth_data . credential_data . credential_id [:])
badid [ len ( badid ) // 2 ] = badid [ len ( badid ) // 2 ] ^ 1
badid = bytes ( badid )
allow_list = [{ "id" : badid , "type" : "public-key" }]
with pytest . raises ( CtapError ) as e :
2019-08-08 03:05:15 +02:00
device . sendGA ( * FidoRequest ( allow_list = allow_list ) . toGA ())
2019-08-05 13:40:54 +08:00
assert e . value . code == CtapError . ERR . NO_CREDENTIALS
2019-09-16 15:34:42 +08:00
def test_mismatched_rp ( self , device , GARes ):
rp_id = GARes . request . rp [ 'id' ][:]
rp_name = GARes . request . rp [ 'name' ][:]
rp_id += '.com'
mismatch_rp = { 'id' : rp_id , 'name' : rp_name }
with pytest . raises ( CtapError ) as e :
device . sendGA ( * FidoRequest ( GARes , rp = mismatch_rp ) . toGA ())
assert e . value . code == CtapError . ERR . NO_CREDENTIALS
2019-08-08 03:05:15 +02:00
def test_missing_rp ( self , device , GARes ):
2019-08-05 13:40:54 +08:00
with pytest . raises ( CtapError ) as e :
2019-08-08 03:05:15 +02:00
device . sendGA ( * FidoRequest ( GARes , rp = None ) . toGA ())
2019-08-05 13:40:54 +08:00
assert e . value . code == CtapError . ERR . MISSING_PARAMETER
2019-08-08 03:05:15 +02:00
def test_bad_rp ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
2019-08-08 03:05:15 +02:00
device . sendGA ( * FidoRequest ( GARes , rp = { "id" : { "type" : "wrong" }}) . toGA ())
2019-08-05 20:02:20 +08:00
2019-08-08 03:05:15 +02:00
def test_missing_cdh ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
2019-08-08 03:05:15 +02:00
device . sendGA ( * FidoRequest ( GARes , cdh = None ) . toGA ())
2019-08-05 20:02:20 +08:00
assert e . value . code == CtapError . ERR . MISSING_PARAMETER
2019-08-08 03:05:15 +02:00
def test_bad_cdh ( self , device , GARes ):
with pytest . raises ( CtapError ) as e :
device . sendGA ( * FidoRequest ( GARes , cdh = { "type" : "wrong" }) . toGA ())
def test_bad_allow_list ( self , device , GARes ):
with pytest . raises ( CtapError ) as e :
device . sendGA ( * FidoRequest ( GARes , allow_list = { "type" : "wrong" }) . toGA ())
def test_bad_allow_list_item ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes , allow_list = [ "wrong" ] + GARes . request . allow_list
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-08 03:05:15 +02:00
def test_unknown_option ( self , device , GARes ):
device . sendGA ( * FidoRequest ( GARes , options = { "unknown" : True }) . toGA ())
2019-08-05 20:02:20 +08:00
2019-10-08 13:03:41 +02:00
@pytest.mark.skipif ( 'trezor' in sys . argv , reason = "User verification flag is intentionally set to true on Trezor even when user verification is not configured. (Otherwise some services refuse registration without giving a reason.)" )
2019-08-08 03:05:15 +02:00
def test_option_uv ( self , device , info , GARes ):
2019-08-05 20:02:20 +08:00
if "uv" in info . options :
if info . options [ "uv" ]:
2019-08-08 03:05:15 +02:00
res = device . sendGA ( * FidoRequest ( GARes , options = { "uv" : True }) . toGA ())
2019-08-05 20:02:20 +08:00
assert res . auth_data . flags & ( 1 << 2 )
2019-08-08 03:05:15 +02:00
def test_option_up ( self , device , info , GARes ):
2019-08-05 20:02:20 +08:00
if "up" in info . options :
if info . options [ "up" ]:
2019-08-08 03:05:15 +02:00
res = device . sendGA ( * FidoRequest ( GARes , options = { "up" : True }) . toGA ())
2019-08-05 20:02:20 +08:00
assert res . auth_data . flags & ( 1 << 0 )
2019-08-08 03:05:15 +02:00
def test_allow_list_fake_item ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes ,
allow_list = [{ "type" : "rot13" , "id" : b "1234" }]
+ GARes . request . allow_list ,
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-08 03:05:15 +02:00
def test_allow_list_missing_field ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes , allow_list = [{ "id" : b "1234" }] + GARes . request . allow_list
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-08 03:05:15 +02:00
def test_allow_list_field_wrong_type ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes ,
allow_list = [{ "type" : b "public-key" , "id" : b "1234" }]
+ GARes . request . allow_list ,
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-08 03:05:15 +02:00
def test_allow_list_id_wrong_type ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes ,
2019-09-30 14:20:16 +02:00
allow_list = [{ "type" : "public-key" , "id" : 42 }]
2019-08-08 03:05:15 +02:00
+ GARes . request . allow_list ,
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-08 03:05:15 +02:00
def test_allow_list_missing_id ( self , device , GARes ):
2019-08-05 20:02:20 +08:00
with pytest . raises ( CtapError ) as e :
device . sendGA (
2019-08-08 03:05:15 +02:00
* FidoRequest (
GARes ,
2019-09-30 14:20:16 +02:00
allow_list = [{ "type" : "public-key" }] + GARes . request . allow_list ,
2019-08-08 03:05:15 +02:00
) . toGA ()
2019-08-05 20:02:20 +08:00
)
2019-08-05 13:40:54 +08:00
2019-09-16 16:26:47 +08:00
def test_user_presence_option_false ( self , device , MCRes , GARes ):
2019-10-08 13:00:40 +02:00
from cryptography.exceptions import InvalidSignature
2019-09-16 16:26:47 +08:00
res = device . sendGA ( * FidoRequest ( GARes , options = { 'up' : False }) . toGA ())
2019-10-08 13:00:40 +02:00
try :
verify ( MCRes , res , GARes . request . cdh )
except InvalidSignature :
if 'trezor' not in sys . argv :
raise
2019-09-16 16:26:47 +08:00
if '--nfc' not in sys . argv :
assert (( res . auth_data . flags & 1 ) == 0 )
2019-08-05 13:40:54 +08:00
2019-10-08 13:18:54 +02:00
@pytest.mark.skipif ( 'trezor' in sys . argv , reason = "Reboot is not supported on Trezor." )
2019-08-05 13:40:54 +08:00
class TestGetAssertionAfterBoot ( object ):
2019-08-08 03:05:15 +02:00
def test_assertion_after_reboot ( self , rebootedDevice , MCRes , GARes ):
2019-08-05 13:40:54 +08:00
credential_data = AttestedCredentialData ( MCRes . auth_data . credential_data )
verify ( MCRes , GARes )