From 7a7dcc7329405061bce430061584a20724ff1eda Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Tue, 17 Mar 2020 14:20:45 -0700 Subject: [PATCH] Fix for Extended APDUs Not all Java Cards that support extended APDUs have APDU buffer lengths long enough to include the attestation certificate. This causes registration to fail when extended APDUs are used, as is the case with iOS. The fix is to build the extended responses incrementally instead of staging them all at once in the APDU buffer. --- src/main/java/com/ledger/u2f/U2FApplet.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ledger/u2f/U2FApplet.java b/src/main/java/com/ledger/u2f/U2FApplet.java index 0ff8942..4e50410 100644 --- a/src/main/java/com/ledger/u2f/U2FApplet.java +++ b/src/main/java/com/ledger/u2f/U2FApplet.java @@ -190,18 +190,19 @@ private void handleEnroll(APDU apdu) throws ISOException { attestationSignature.update(scratch, SCRATCH_KEY_HANDLE_OFFSET, keyHandleLength); attestationSignature.update(scratch, SCRATCH_PUBLIC_KEY_OFFSET, (short)65); outOffset = (short)(ENROLL_PUBLIC_KEY_OFFSET + 65 + 1 + keyHandleLength); + short signatureSize = attestationSignature.sign(buffer, (short)0, (short)0, scratch, SCRATCH_SIGNATURE_OFFSET); + if (extendedLength) { // If using extended length, the message can be completed and sent immediately scratch[SCRATCH_TRANSPORT_STATE] = TRANSPORT_EXTENDED; - outOffset = Util.arrayCopyNonAtomic(scratch, SCRATCH_PAD, buffer, (short)0, outOffset); - outOffset = Util.arrayCopyNonAtomic(attestationCertificate, (short)0, buffer, outOffset, (short)attestationCertificate.length); - short signatureSize = attestationSignature.sign(buffer, (short)0, (short)0, buffer, outOffset); - outOffset += signatureSize; - apdu.setOutgoingAndSend((short)0, outOffset); + apdu.setOutgoing(); + apdu.setOutgoingLength((short)(outOffset + attestationCertificate.length + signatureSize)); + apdu.sendBytesLong(scratch, SCRATCH_PAD, outOffset); + apdu.sendBytesLong(attestationCertificate, (short)0, (short)attestationCertificate.length); + apdu.sendBytesLong(scratch, SCRATCH_SIGNATURE_OFFSET, signatureSize); } else { // Otherwise, keep the signature and proceed to send the first chunk - short signatureSize = attestationSignature.sign(buffer, (short)0, (short)0, scratch, SCRATCH_SIGNATURE_OFFSET); scratch[SCRATCH_TRANSPORT_STATE] = TRANSPORT_NOT_EXTENDED; Util.setShort(scratch, SCRATCH_CURRENT_OFFSET, (short)0); Util.setShort(scratch, SCRATCH_SIGNATURE_LENGTH, signatureSize); @@ -285,8 +286,9 @@ private void handleSign(APDU apdu) throws ISOException { if (extendedLength) { // If using extended length, the message can be completed and sent immediately scratch[SCRATCH_TRANSPORT_STATE] = TRANSPORT_EXTENDED; - Util.arrayCopyNonAtomic(scratch, SCRATCH_PAD, buffer, (short)0, outOffset); - apdu.setOutgoingAndSend((short)0, (short)(outOffset - SCRATCH_PAD)); + apdu.setOutgoing(); + apdu.setOutgoingLength((short)(outOffset - SCRATCH_PAD)); + apdu.sendBytesLong(scratch, SCRATCH_PAD, (short)(outOffset - SCRATCH_PAD)); } else { // Otherwise send the first chunk