diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 992ee55c..3ff962ab 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1984,7 +1984,20 @@ private void finishAesDesOperation(KMOperationState op) { KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff()); } catch (CryptoException e) { if (e.getReason() == CryptoException.ILLEGAL_USE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + // As per VTS, zero length input on AES/DES with PADDING_NONE Should return a zero length + // output. But JavaCard fails with CryptoException.ILLEGAL_USE if no input data is + // provided via update() method. So ignore this exception in case if all below conditions + // are satisfied and simply return empty output. + // 1. padding mode is PADDING_NONE. + // 2. No input message is processed in update(). + // 3. Zero length input data is passed in finish operation. + if ((op.getPadding() == KMType.PADDING_NONE) && + !op.isInputMsgProcessed() && + (KMByteBlob.cast(data[INPUT_DATA]).length() == 0)) { + len = 0; + } else { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } } } @@ -2436,6 +2449,13 @@ private void processUpdateOperationCmd(APDU apdu) { } catch (CryptoException e) { KMException.throwIt(KMError.INVALID_TAG); } + if (KMByteBlob.cast(data[INPUT_DATA]).length() > 0) { + // This flag is used to denote that an input data of length > 0 is received and processed + // successfully in update command. This flag is later used in the finish operation + // to handle a particular use case, where a zero length input data on AES/DES algorithm + // with PADDING_NONE should return a zero length output with OK response. + op.setProcessedInputMsg(true); + } // Adjust the Output data if it is not equal to input data. // This happens in case of JCardSim provider. KMByteBlob.cast(data[OUTPUT_DATA]).setLength(tmpVariables[0]); diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 1daafabe..d7310817 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -55,6 +55,7 @@ public class KMOperationState { private static final byte SECURE_USER_ID_REQD = 2; private static final byte AUTH_TIMEOUT_VALIDATED = 4; private static final byte AES_GCM_UPDATE_ALLOWED = 8; + private static final byte PROCESSED_INPUT_MSG = 16; private static final byte MAX_SECURE_USER_IDS = 5; // Object References @@ -153,6 +154,10 @@ public void setOperation(KMOperation opr) { persist(); } + public boolean isInputMsgProcessed() { + return (data[FLAGS] & PROCESSED_INPUT_MSG) != 0; + } + public KMOperation getOperation() { return (KMOperation) objRefs[OPERATION]; } @@ -230,6 +235,15 @@ public void setUserSecureId(short integerArrayPtr) { dataUpdated(); } + public void setProcessedInputMsg(boolean flag) { + if (flag) { + data[FLAGS] = (byte) (data[FLAGS] | PROCESSED_INPUT_MSG); + } else { + data[FLAGS] = (byte) (data[FLAGS] & (~PROCESSED_INPUT_MSG)); + } + dataUpdated(); + } + public void setOneTimeAuthReqd(boolean flag) { if (flag) { data[FLAGS] = (byte) (data[FLAGS] | SECURE_USER_ID_REQD);