Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -1776,7 +1776,19 @@ 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);
}
}
}
KMByteBlob.cast(data[OUTPUT_DATA]).setLength(len);
Expand DownExpand Up@@ -2136,7 +2148,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(len);
Expand Down
13 changes: 13 additions & 0 deletions Applet/src/com/android/javacard/keymaster/KMOperationState.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -56,6 +56,7 @@ public class KMOperationState {
private static final short SECURE_USER_ID_REQD = 2;
private static final short AUTH_TIMEOUT_VALIDATED = 4;
private static final short AES_GCM_UPDATE_ALLOWED = 8;
private static final byte PROCESSED_INPUT_MSG = 16;
// Max user secure ids.
private static final byte MAX_SECURE_USER_IDS = 5;

Expand DownExpand Up@@ -122,6 +123,10 @@ public void setPurpose(short purpose) {
data[PURPOSE] = purpose;
}

public boolean isInputMsgProcessed() {
return (data[FLAGS] & PROCESSED_INPUT_MSG) != 0;
}

public void setOperation(KMOperation op) {
operations[OPERATION] = op;
}
Expand DownExpand Up@@ -150,6 +155,14 @@ public void setAuthTime(byte[] timeBuf, short start) {
Util.arrayCopyNonAtomic(timeBuf, start, authTime, (short) 0, AUTH_TIME_SIZE);
}

public void setProcessedInputMsg(boolean flag) {
if (flag) {
data[FLAGS] = (byte) (data[FLAGS] | PROCESSED_INPUT_MSG);
} else {
data[FLAGS] = (byte) (data[FLAGS] & (~PROCESSED_INPUT_MSG));
}
}

public void setOneTimeAuthReqd(boolean flag) {
if (flag) {
data[FLAGS] = (short) (data[FLAGS] | SECURE_USER_ID_REQD);
Expand Down