@@ -1152,6 +1152,14 @@ private short checkIfPubKeyBlockSupported(APDU apdu, short readIdx, short lc) {
11521152 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_CBOR_UNEXPECTED_TYPE );
11531153 }
11541154 short typeValLen = (short ) (bufferMem [readIdx ] & 0x0F );
1155+ if (typeValLen != CannedCBOR .PUBLIC_KEY_TYPE .length ) {
1156+ // not the same length as type "public-key": can't be a match
1157+ transientStorage .resetFoundKeyMatch ();
1158+ } else if (Util .arrayCompare (bufferMem , (short )(readIdx + 1 ),
1159+ CannedCBOR .PUBLIC_KEY_TYPE , (short ) 0 , typeValLen ) != 0 ) {
1160+ // Not of type "public-key", although same length
1161+ transientStorage .resetFoundKeyMatch ();
1162+ }
11551163 readIdx += typeValLen + 1 ;
11561164 if (readIdx >= lc ) {
11571165 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_INVALID_CBOR );
@@ -2507,7 +2515,22 @@ public void process(APDU apdu) throws ISOException {
25072515
25082516 byte [] apduBytes = apdu .getBuffer ();
25092517
2510- if (apduBytes [ISO7816 .OFFSET_CLA ] == 0x00 && apduBytes [ISO7816 .OFFSET_INS ] == (byte ) 0xC0 ) {
2518+ byte cla = apduBytes [ISO7816 .OFFSET_CLA ];
2519+ byte ins = apduBytes [ISO7816 .OFFSET_INS ];
2520+
2521+ if (cla == (byte ) 0x80 && ins == 0x12 && apduBytes [ISO7816 .OFFSET_P1 ] == 0x01
2522+ && apduBytes [ISO7816 .OFFSET_P2 ] == 0x00 ) {
2523+ // Explicit disable command (NFCCTAP_CONTROL end CTAP_MSG). Turn off, and stay off.
2524+ transientStorage .disableAuthenticator ();
2525+ }
2526+
2527+ if (transientStorage .authenticatorDisabled ()) {
2528+ return ;
2529+ }
2530+
2531+ if ((cla == 0x00 || cla == (byte ) 0x80 )
2532+ && ins == (byte ) 0xC0 ) {
2533+ // continue outgoing response from buffer
25112534 if (transientStorage .getOutgoingContinuationRemaining () == 0 ) {
25122535 throwException (ISO7816 .SW_CONDITIONS_NOT_SATISFIED );
25132536 }
@@ -2539,6 +2562,7 @@ public void process(APDU apdu) throws ISOException {
25392562 }
25402563
25412564 if (apdu .isCommandChainingCLA ()) {
2565+ // Incoming chained request
25422566 short amtRead = apdu .setIncomingAndReceive ();
25432567
25442568 short lc = apdu .getIncomingLength ();
@@ -2552,7 +2576,7 @@ public void process(APDU apdu) throws ISOException {
25522576 return ;
25532577 }
25542578
2555- if (apduBytes [ISO7816 .OFFSET_CLA ] != (byte )0x80 ) {
2579+ if (apduBytes [ISO7816 .OFFSET_CLA ] != (byte ) 0x80 ) {
25562580 throwException (ISO7816 .SW_CLA_NOT_SUPPORTED );
25572581 }
25582582
@@ -2568,7 +2592,7 @@ public void process(APDU apdu) throws ISOException {
25682592 short lc = apdu .getIncomingLength ();
25692593
25702594 if (amtRead == 0 ) {
2571- throwException (ISO7816 .SW_UNKNOWN );
2595+ throwException (ISO7816 .SW_DATA_INVALID );
25722596 }
25732597
25742598 short incomingOffset = 1 ;
@@ -2726,7 +2750,7 @@ private void credManagementSubcommand(APDU apdu, short lc, short readIdx) {
27262750 short scratchAmt = (short )(1 + subCommandParamsLen );
27272751 short scratchOff = scratchAlloc (scratchAmt );
27282752 scratch [scratchOff ] = bufferMem [subcommandIdx ];
2729- if (subCommandParamsLen > CREDENTIAL_ID_LEN + MAX_USER_ID_LENGTH + 30 ) {
2753+ if (subCommandParamsLen > CREDENTIAL_ID_LEN + MAX_USER_ID_LENGTH + 35 ) {
27302754 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_REQUEST_TOO_LARGE );
27312755 }
27322756 if (subCommandParamsLen > 0 ) {
@@ -2827,29 +2851,33 @@ private void handleUserUpdate(APDU apdu, short readOffset, short lc) {
28272851 // Don't need to decrypt creds, just byte-compare them
28282852 if (Util .arrayCompare (residentKeyData , (short )(i * CREDENTIAL_ID_LEN ),
28292853 bufferMem , credIdIdx , CREDENTIAL_ID_LEN ) == 0 ) {
2830- // Credential matches - check user ID
2854+ // Matching cred.
2855+ // We need to extract the credential to check that our PIN token WOULD have permission
2856+ short scratchExtractedCred = scratchAlloc (CREDENTIAL_ID_LEN );
2857+ symmetricUnwrapper .doFinal (residentKeyData , (short )(i * CREDENTIAL_ID_LEN ), CREDENTIAL_ID_LEN ,
2858+ scratch , scratchExtractedCred
2859+ );
2860+ if (permissionsRpId [0 ] != 0x00 ) {
2861+ if (Util .arrayCompare (scratch , (short )(scratchExtractedCred + 32 ),
2862+ permissionsRpId , (short ) 1 , RP_HASH_LEN ) != 0 ) {
2863+ // permissions RP ID in use, but doesn't match RP of this credential
2864+ sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
2865+ }
2866+ }
2867+
2868+ // Now that we have permission, check the user ID
28312869 symmetricUnwrapper .doFinal (residentKeyUserIds , (short )(i * MAX_USER_ID_LENGTH ), MAX_USER_ID_LENGTH ,
28322870 scratch , uidOffset );
28332871 if (Util .arrayCompare (scratch , uidOffset ,
2834- bufferMem ,userIdIdx ,userIdLen ) == 0 ) {
2872+ bufferMem , userIdIdx , userIdLen ) == 0 ) {
28352873 // Matches both credential and user ID - it's a hit.
2836- // No actual updating work to do here because we don't store anything other than the ID...
2837-
2838- // ... but we need to extract the credential to check that our PIN token WOULD have permission
2839- short scratchExtractedCred = scratchAlloc (CREDENTIAL_ID_LEN );
2840- symmetricUnwrapper .doFinal (residentKeyData , (short )(i * CREDENTIAL_ID_LEN ), CREDENTIAL_ID_LEN ,
2841- scratch , scratchExtractedCred
2842- );
2843- if (permissionsRpId [0 ] != 0x00 ) {
2844- if (Util .arrayCompare (scratch , (short )(scratchExtractedCred + 32 ),
2845- permissionsRpId , (short ) 1 , RP_HASH_LEN ) != 0 ) {
2846- // permissions RP ID in use, but doesn't match RP of this credential
2847- sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
2848- }
2849- }
2874+ // No actual updating work to do here because we don't store anything other than the ID
28502875
28512876 foundHit = true ;
28522877 break ;
2878+ } else {
2879+ // matches credential ID, but doesn't match user ID
2880+ sendErrorByte (apdu , FIDOConstants .CTAP1_ERR_INVALID_PARAMETER );
28532881 }
28542882 }
28552883 }
@@ -3505,7 +3533,7 @@ private void handleClientPinChange(APDU apdu, short readIdx, short lc, byte pinP
35053533 break ;
35063534 }
35073535 }
3508- if (realPinLength < 4 ) {
3536+ if (realPinLength < 4 || realPinLength > 63 ) {
35093537 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_POLICY_VIOLATION );
35103538 }
35113539
@@ -3789,7 +3817,7 @@ private void testAndReadyPIN(APDU apdu, byte[] buf, short off, byte pinProtocol,
37893817
37903818 // BAD PIN
37913819 forceInitKeyAgreementKey ();
3792- sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
3820+ sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_INVALID );
37933821 }
37943822
37953823 /**
0 commit comments