@@ -348,7 +348,8 @@ public final class FIDO2Applet extends Applet implements ExtendedLength {
348348 /**
349349 * Storage for the largeBlobs extension
350350 */
351- private final byte [][] largeBlobStores ;
351+ private final byte [] largeBlobStoreA ;
352+ private final byte [] largeBlobStoreB ;
352353 /**
353354 * Which large blob store is in use
354355 */
@@ -3648,6 +3649,20 @@ public void process(APDU apdu) throws ISOException {
36483649 transientStorage .resetChainIncomingReadOffset ();
36493650 }
36503651
3652+ private byte [] getCurrentLargeBlobStore () {
3653+ if (largeBlobStoreIndex == 0 ) {
3654+ return largeBlobStoreA ;
3655+ }
3656+ return largeBlobStoreB ;
3657+ }
3658+
3659+ private byte [] getInactiveLargeBlobStore () {
3660+ if (largeBlobStoreIndex == 1 ) {
3661+ return largeBlobStoreA ;
3662+ }
3663+ return largeBlobStoreB ;
3664+ }
3665+
36513666 /**
36523667 * Processes CTAP2 largeBlob extension commands
36533668 *
@@ -3773,7 +3788,9 @@ private void handleLargeBlobs(APDU apdu, byte[] reqBuffer, short lc) {
37733788 sendErrorByte (apdu , FIDOConstants .CTAP1_ERR_INVALID_PARAMETER );
37743789 }
37753790
3776- if (offset < 0 || offset > (short ) largeBlobStores [largeBlobStoreIndex ].length ) {
3791+ byte [] currentLargeBlobStore = getCurrentLargeBlobStore ();
3792+
3793+ if (offset < 0 || offset > (short ) currentLargeBlobStore .length ) {
37773794 // Offset is mandatory and must be reasonable
37783795 sendErrorByte (apdu , FIDOConstants .CTAP1_ERR_INVALID_PARAMETER );
37793796 }
@@ -3804,7 +3821,7 @@ private void handleLargeBlobs(APDU apdu, byte[] reqBuffer, short lc) {
38043821 if (setTotalLength < 17 ) {
38053822 sendErrorByte (apdu , FIDOConstants .CTAP1_ERR_INVALID_PARAMETER );
38063823 }
3807- if (setTotalLength > (short ) largeBlobStores [ largeBlobStoreIndex ] .length ) {
3824+ if (setTotalLength > (short ) currentLargeBlobStore .length ) {
38083825 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_LARGE_BLOB_STORAGE_FULL );
38093826 }
38103827 } else {
@@ -3875,9 +3892,9 @@ private void handleLargeBlobs(APDU apdu, byte[] reqBuffer, short lc) {
38753892 */
38763893 private void handleLargeBlobSet (APDU apdu , byte [] buffer , short incomingDataOffset ,
38773894 short blobWriteOffset , short incomingDataLength , short totalLength ) {
3878- final byte tempBlobStoreIndex = ( byte )( largeBlobStoreIndex == 0 ? 1 : 0 );
3895+ final byte [] inactiveLargeBlobStore = getInactiveLargeBlobStore ( );
38793896 Util .arrayCopyNonAtomic (buffer , incomingDataOffset ,
3880- largeBlobStores [ tempBlobStoreIndex ] , blobWriteOffset , incomingDataLength );
3897+ inactiveLargeBlobStore , blobWriteOffset , incomingDataLength );
38813898 // Done with incoming request now
38823899 bufferManager .informAPDUBufferAvailability (apdu , (short ) 0xFF );
38833900
@@ -3890,22 +3907,23 @@ private void handleLargeBlobSet(APDU apdu, byte[] buffer, short incomingDataOffs
38903907 byte [] scratch = bufferManager .getBufferForHandle (apdu , scratchHandle );
38913908 short scratchOffset = bufferManager .getOffsetForHandle (scratchHandle );
38923909
3893- sha256 .doFinal (largeBlobStores [ tempBlobStoreIndex ] , (short ) 0 , (short )(totalLength - 16 ),
3910+ sha256 .doFinal (inactiveLargeBlobStore , (short ) 0 , (short )(totalLength - 16 ),
38943911 scratch , scratchOffset );
38953912
38963913 if (Util .arrayCompare (scratch , scratchOffset ,
3897- largeBlobStores [ tempBlobStoreIndex ] , (short )(totalLength - 16 ), (short ) 16 ) != 0 ) {
3914+ inactiveLargeBlobStore , (short )(totalLength - 16 ), (short ) 16 ) != 0 ) {
38983915 // hash mismatch
38993916 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_INTEGRITY_FAILURE );
39003917 }
39013918
39023919 bufferManager .release (apdu , scratchHandle , (short ) 32 );
39033920
39043921 // Swapperoo the buffers
3922+ final byte newBlobStoreIndex = (byte )(largeBlobStoreIndex == 0 ? 1 : 0 );
39053923 JCSystem .beginTransaction ();
39063924 boolean ok = false ;
39073925 try {
3908- largeBlobStoreIndex = tempBlobStoreIndex ;
3926+ largeBlobStoreIndex = newBlobStoreIndex ;
39093927 largeBlobStoreFill = totalLength ;
39103928 } finally {
39113929 if (ok ) {
@@ -3952,7 +3970,7 @@ private void handleLargeBlobGet(APDU apdu, short numBytes, short offset) {
39523970 outBuffer [writeIdx ++] = (byte ) 0xA1 ; // map - one key
39533971 outBuffer [writeIdx ++] = (byte ) 0x01 ; // map key: config
39543972 writeIdx = encodeIntLenTo (outBuffer , writeIdx , bytesToRetrieve , true );
3955- writeIdx = Util .arrayCopyNonAtomic (largeBlobStores [ largeBlobStoreIndex ] , offset ,
3973+ writeIdx = Util .arrayCopyNonAtomic (getCurrentLargeBlobStore () , offset ,
39563974 outBuffer , writeIdx , bytesToRetrieve );
39573975
39583976 if (outBuffer == bufferMem ) {
@@ -5374,10 +5392,12 @@ private void authenticatorReset(APDU apdu) {
53745392 final byte realBlobStoreIndex = largeBlobStoreIndex ;
53755393
53765394 // Empty the large blob store OUTside the main transaction, since it's non-precious and double buffered
5377- Util .arrayFillNonAtomic (largeBlobStores [tempBlobStoreIndex ], (short ) 0 ,
5378- (short ) largeBlobStores [tempBlobStoreIndex ].length , (byte ) 0x00 );
5395+ final byte [] inactiveLargeBlobStore = getInactiveLargeBlobStore ();
5396+ final byte [] activeLargeBlobStore = getCurrentLargeBlobStore ();
5397+ Util .arrayFillNonAtomic (inactiveLargeBlobStore , (short ) 0 ,
5398+ (short ) inactiveLargeBlobStore .length , (byte ) 0x00 );
53795399 Util .arrayCopyNonAtomic (CannedCBOR .INITIAL_LARGE_BLOB_ARRAY , (short ) 0 ,
5380- largeBlobStores [ tempBlobStoreIndex ] , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
5400+ inactiveLargeBlobStore , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
53815401 JCSystem .beginTransaction ();
53825402 boolean ok = false ;
53835403 try {
@@ -5391,10 +5411,10 @@ private void authenticatorReset(APDU apdu) {
53915411 JCSystem .abortTransaction ();
53925412 }
53935413 }
5394- Util .arrayFillNonAtomic (largeBlobStores [ realBlobStoreIndex ] , (short ) 0 ,
5395- (short ) largeBlobStores [ realBlobStoreIndex ] .length , (byte ) 0x00 );
5414+ Util .arrayFillNonAtomic (activeLargeBlobStore , (short ) 0 ,
5415+ (short ) activeLargeBlobStore .length , (byte ) 0x00 );
53965416 Util .arrayCopyNonAtomic (CannedCBOR .INITIAL_LARGE_BLOB_ARRAY , (short ) 0 ,
5397- largeBlobStores [ realBlobStoreIndex ] , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
5417+ activeLargeBlobStore , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
53985418
53995419 JCSystem .beginTransaction ();
54005420 ok = false ;
@@ -5594,7 +5614,7 @@ private void sendAuthInfo(APDU apdu) {
55945614
55955615 buffer [offset ++] = 0x0B ; // map key: maxSerializedLargeBlobArray: 1 byte = 5
55965616 buffer [offset ++] = 0x19 ; // two-byte integer: 1 byte = 6
5597- offset = Util .setShort (buffer , offset , (short ) largeBlobStores [ largeBlobStoreIndex ] .length ); // 2 bytes = 8
5617+ offset = Util .setShort (buffer , offset , (short ) getCurrentLargeBlobStore () .length ); // 2 bytes = 8
55985618
55995619 buffer [offset ++] = 0x0C ; // map key: forcePinChange: 1 byte = 9
56005620 buffer [offset ++] = (byte )(forcePinChange ? 0xF5 : 0xF4 ); // 1 byte = 10
@@ -6818,11 +6838,12 @@ private FIDO2Applet(byte[] array, short offset, byte length) {
68186838 highSecurityWrappingIV = new byte [IV_LEN ];
68196839 lowSecurityWrappingIV = new byte [IV_LEN ];
68206840 externalCredentialIV = new byte [IV_LEN ];
6821- largeBlobStores = new byte [ 2 ] [largeBlobStoreSize ];
6841+ largeBlobStoreA = new byte [largeBlobStoreSize ];
68226842 Util .arrayCopyNonAtomic (CannedCBOR .INITIAL_LARGE_BLOB_ARRAY , (short ) 0 ,
6823- largeBlobStores [0 ], (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
6843+ largeBlobStoreA , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
6844+ largeBlobStoreB = new byte [largeBlobStoreSize ];
68246845 Util .arrayCopyNonAtomic (CannedCBOR .INITIAL_LARGE_BLOB_ARRAY , (short ) 0 ,
6825- largeBlobStores [ 1 ] , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
6846+ largeBlobStoreB , (short ) 0 , (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length );
68266847 largeBlobStoreFill = (short ) CannedCBOR .INITIAL_LARGE_BLOB_ARRAY .length ;
68276848 highSecurityWrappingKey = getTransientAESKey (); // Our most important treasure, from which all other crypto is born...
68286849 lowSecurityWrappingKey = getPersistentAESKey (); // Not really a treasure
0 commit comments