@@ -17,11 +17,9 @@ public final class FIDO2Applet extends Applet implements ExtendedLength {
1717 */
1818 private static final byte FIRMWARE_VERSION = 0x01 ;
1919 /**
20- * If true, permit the creation of resident keys without a PIN being set or provided.
21- * This is "normal" for a FIDO2 authenticator, but means keys on the device could be
22- * accessed in the event of a software bug or hardware fault.
20+ * If true, default the `alwaysUv` option to on, and prevent disabling it.
2321 */
24- private static final boolean ALLOW_RESIDENT_KEY_CREATION_WITHOUT_PIN = true ;
22+ private static final boolean FORCE_ALWAYS_UV = false ;
2523 /**
2624 * If true, the authenticator will refuse to reset itself until the following three steps happen in order:
2725 * <p>
@@ -305,7 +303,7 @@ public final class FIDO2Applet extends Applet implements ExtendedLength {
305303 /**
306304 * Set to true when the use of a PIN is forced for all operations
307305 */
308- private boolean alwaysUv ;
306+ private boolean alwaysUv = FORCE_ALWAYS_UV ;
309307 /**
310308 * Everything that needs to be hot in RAM instead of stored to the flash. All goes away on deselect or reset!
311309 */
@@ -787,10 +785,6 @@ private void makeCredential(APDU apdu, short lc, byte[] buffer) {
787785 // OR: PIN not set, but we've been asked not to do this without one
788786 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_REQUIRED );
789787 }
790- if (!ALLOW_RESIDENT_KEY_CREATION_WITHOUT_PIN && transientStorage .hasRKOption ()) {
791- // Don't allow storing resident keys without a PIN set
792- sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_OPERATION_DENIED );
793- }
794788 }
795789 loadWrappingKeyIfNoPIN ();
796790
@@ -1376,10 +1370,16 @@ private void verifyPinAuth(APDU apdu, byte[] buffer, short readIdx,
13761370 if (len >= (byte ) 0x40 && len <= (byte ) 0x57 ) {
13771371 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
13781372 }
1373+ if (len == 0x58 ) {
1374+ sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
1375+ }
13791376 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_CBOR_UNEXPECTED_TYPE );
13801377 }
13811378 } else {
13821379 if (len != 0x58 ) { // byte array, one-byte length
1380+ if (len >= 0x40 && len <= 0x57 ) {
1381+ sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_AUTH_INVALID );
1382+ }
13831383 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_CBOR_UNEXPECTED_TYPE );
13841384 }
13851385 if (buffer [readIdx ++] != desiredLength ) {
@@ -3601,7 +3601,7 @@ private void handleLargeBlobs(APDU apdu, byte[] reqBuffer, short lc) {
36013601 }
36023602 }
36033603
3604- if (pinSet ) {
3604+ if (pinSet || alwaysUv ) {
36053605 if (pinUvAuthIdx == -1 ) {
36063606 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_PIN_REQUIRED );
36073607 }
@@ -4277,6 +4277,9 @@ private void setMinPin(APDU apdu, byte[] buffer, short readIdx, short cmdParamsL
42774277 * @param apdu Request/response context object
42784278 */
42794279 private void toggleAlwaysUv (APDU apdu ) {
4280+ if (FORCE_ALWAYS_UV ) {
4281+ sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_OPERATION_DENIED );
4282+ }
42804283 alwaysUv = !alwaysUv ;
42814284
42824285 apdu .getBuffer ()[0 ] = FIDOConstants .CTAP2_OK ;
@@ -5083,7 +5086,7 @@ private void authenticatorReset(APDU apdu) {
50835086 pinSet = false ;
50845087 minPinLength = 4 ;
50855088 forcePinChange = false ;
5086- alwaysUv = false ;
5089+ alwaysUv = FORCE_ALWAYS_UV ;
50875090 pinRetryCounter .reset (pinIdx );
50885091 Util .arrayFillNonAtomic (largeBlobStore , (short ) 0 , LARGE_BLOB_STORE_MAX_SIZE , (byte ) 0x00 );
50895092 Util .arrayCopyNonAtomic (CannedCBOR .INITIAL_LARGE_BLOB_ARRAY , (short ) 0 ,
0 commit comments