Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions python_tests/ctap/test_credprotect.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,40 @@ def test_low_sec_credprotect(self):
'up': False
})

def test_credprotect_three_creation_requires_pin_when_pin_set(self):
pin = secrets.token_hex(8)
ClientPin(self.ctap2).set_pin(pin)

params = dict(self.basic_makecred_params)
params['extensions'] = {
"credProtect": CredProtectExtension.POLICY.REQUIRED
}

with self.assertRaises(CtapError) as e:
self.ctap2.make_credential(**params)

self.assertEqual(CtapError.ERR.PIN_REQUIRED, e.exception.code)


class MaximumComplianceCredProtectTestCase(CredProtectTestCase):
def setUp(self, install_params=None) -> None:
if install_params is None:
install_params = bytes([0xA2, 0x00, 0xF5, 0x01, 0xF5])
super().setUp(install_params=install_params)

def test_level_three_can_use_low_security_when_explicitly_enabled(self):
pin = secrets.token_hex(8)
ClientPin(self.ctap2).set_pin(pin)

params = dict(self.basic_makecred_params)
params['extensions'] = {
"credProtect": CredProtectExtension.POLICY.REQUIRED
}

res = self.ctap2.make_credential(**params)
self.assertEqual(CredProtectExtension.POLICY.REQUIRED,
res.auth_data.extensions.get('credProtect'))


class CredProtectDeletionTestCase(CredManagementBaseTestCase):
@parameterized.expand([
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/us/q3q/fido2/FIDO2Applet.java
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,8 @@ private void makeCredential(APDU apdu, short lc, byte[] buffer) {
effectiveCredBlobLen = 0;
}

final boolean lowSecForRK = USE_LOW_SECURITY_FOR_SOME_RKS && credProtectLevel < 3;
final boolean lowSecForRK = (USE_LOW_SECURITY_FOR_SOME_RKS && credProtectLevel < 3)
|| LOW_SECURITY_MAXIMUM_COMPLIANCE;
final boolean lowSecWasUsed = encodeCredentialID(apdu, (ECPrivateKey) ecKeyPair.getPrivate(),
scratchRPIDHashBuffer, scratchRPIDHashOffset,
scratchCredBuffer, scratchCredOffset,
Expand Down Expand Up @@ -1119,7 +1120,8 @@ private void makeCredential(APDU apdu, short lc, byte[] buffer) {
}
} else {
// Non-resident credProtect Level 3 creds still need to use the high security key (to require PIN auth)
final boolean credMayUseLowSecurityForDiscoverable = credProtectLevel < 3;
final boolean credMayUseLowSecurityForDiscoverable = credProtectLevel < 3
|| LOW_SECURITY_MAXIMUM_COMPLIANCE;
encodeCredentialID(apdu, (ECPrivateKey) ecKeyPair.getPrivate(),
scratchRPIDHashBuffer, scratchRPIDHashOffset,
scratchCredBuffer, scratchCredOffset,
Expand Down Expand Up @@ -1772,13 +1774,18 @@ private boolean encodeCredentialID(APDU apdu, ECPrivateKey privKey,
byte[] rpIdHashBuffer, short rpIdHashOffset,
byte[] outBuffer, short outOffset,
short rkNum, boolean lowSecurity, byte credProtectLevel) {
final boolean lowSecurityExplicitlyRequested = lowSecurity;
if (rkNum >= 0 && !USE_LOW_SECURITY_FOR_SOME_RKS) {
lowSecurity = false;
}
// use low security even for RKs if LOW_SECURITY_MAXIMUM_COMPLIANCE
if (LOW_SECURITY_MAXIMUM_COMPLIANCE) {
// use low security even for RKs if LOW_SECURITY_MAXIMUM_COMPLIANCE is explicitly requested
if (LOW_SECURITY_MAXIMUM_COMPLIANCE && (lowSecurity || credProtectLevel < 3)) {
lowSecurity = true;
}
// regardless of anything else, default to the high-sec key for credProtect-level-3 creds unless explicitly requested
if (credProtectLevel == 3 && !lowSecurityExplicitlyRequested) {
lowSecurity = false;
}
// regardless of anything else, opportunistically use the high-sec key for credProtect-level-3 creds
final byte pinProtocolInUse = transientStorage.getPinProtocolInUse();
if (credProtectLevel == 3 && (pinProtocolInUse == 1 || pinProtocolInUse == 2)) {
Expand Down Expand Up @@ -6826,7 +6833,7 @@ private FIDO2Applet(byte[] array, short offset, byte length) {
// set up parameters
// first, defaults
attestationSwitchingEnabled = false;
LOW_SECURITY_MAXIMUM_COMPLIANCE = true;
LOW_SECURITY_MAXIMUM_COMPLIANCE = false;
FORCE_ALWAYS_UV = false;
USE_LOW_SECURITY_FOR_SOME_RKS = true;
PROTECT_AGAINST_MALICIOUS_RESETS = false;
Expand Down
Loading