am 5d586dd5: Merge "KM module may consume less input than provided by finish time." into mnc-dev
* commit '5d586dd585a6663290b68abce433a75b5760fc5d': KM module may consume less input than provided by finish time.
This commit is contained in:
@@ -19,12 +19,14 @@ package android.security.keystore;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.security.KeyStore;
|
import android.security.KeyStore;
|
||||||
import android.security.KeyStoreException;
|
import android.security.KeyStoreException;
|
||||||
|
import android.security.keymaster.KeymasterDefs;
|
||||||
import android.security.keymaster.OperationResult;
|
import android.security.keymaster.OperationResult;
|
||||||
|
|
||||||
import libcore.util.EmptyArray;
|
import libcore.util.EmptyArray;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.ProviderException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
|
* Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
|
||||||
@@ -135,14 +137,15 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
mBuffered = EmptyArray.BYTE;
|
mBuffered = EmptyArray.BYTE;
|
||||||
mBufferedOffset = 0;
|
mBufferedOffset = 0;
|
||||||
mBufferedLength = 0;
|
mBufferedLength = 0;
|
||||||
} else if (opResult.inputConsumed == 0) {
|
} else if (opResult.inputConsumed <= 0) {
|
||||||
// Nothing was consumed. More input needed.
|
// Nothing was consumed. More input needed.
|
||||||
if (inputLength > 0) {
|
if (inputLength > 0) {
|
||||||
// More input is available, but it wasn't included into the previous chunk
|
// More input is available, but it wasn't included into the previous chunk
|
||||||
// because the chunk reached its maximum permitted size.
|
// because the chunk reached its maximum permitted size.
|
||||||
// Shouldn't have happened.
|
// Shouldn't have happened.
|
||||||
throw new IllegalStateException("Nothing consumed from max-sized chunk: "
|
throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
|
||||||
+ chunk.length + " bytes");
|
"Keystore consumed nothing from max-sized chunk: " + chunk.length
|
||||||
|
+ " bytes");
|
||||||
}
|
}
|
||||||
mBuffered = chunk;
|
mBuffered = chunk;
|
||||||
mBufferedOffset = 0;
|
mBufferedOffset = 0;
|
||||||
@@ -153,8 +156,9 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
mBufferedOffset = opResult.inputConsumed;
|
mBufferedOffset = opResult.inputConsumed;
|
||||||
mBufferedLength = chunk.length - opResult.inputConsumed;
|
mBufferedLength = chunk.length - opResult.inputConsumed;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Consumed more than provided: "
|
throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
|
||||||
+ opResult.inputConsumed + ", provided: " + chunk.length);
|
"Keystore consumed more input than provided. Provided: " + chunk.length
|
||||||
|
+ ", consumed: " + opResult.inputConsumed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opResult.output != null) && (opResult.output.length > 0)) {
|
if ((opResult.output != null) && (opResult.output.length > 0)) {
|
||||||
@@ -165,7 +169,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
try {
|
try {
|
||||||
bufferedOutput.write(opResult.output);
|
bufferedOutput.write(opResult.output);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to buffer output", e);
|
throw new ProviderException("Failed to buffer output", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -179,7 +183,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
try {
|
try {
|
||||||
bufferedOutput.write(opResult.output);
|
bufferedOutput.write(opResult.output);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to buffer output", e);
|
throw new ProviderException("Failed to buffer output", e);
|
||||||
}
|
}
|
||||||
result = bufferedOutput.toByteArray();
|
result = bufferedOutput.toByteArray();
|
||||||
}
|
}
|
||||||
@@ -229,11 +233,11 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
return EmptyArray.BYTE;
|
return EmptyArray.BYTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep invoking the update operation with remaining buffered data until either all of the
|
||||||
|
// buffered data is consumed or until update fails to consume anything.
|
||||||
|
ByteArrayOutputStream bufferedOutput = null;
|
||||||
|
while (mBufferedLength > 0) {
|
||||||
byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
|
byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
|
||||||
mBuffered = EmptyArray.BYTE;
|
|
||||||
mBufferedLength = 0;
|
|
||||||
mBufferedOffset = 0;
|
|
||||||
|
|
||||||
OperationResult opResult = mKeyStoreStream.update(chunk);
|
OperationResult opResult = mKeyStoreStream.update(chunk);
|
||||||
if (opResult == null) {
|
if (opResult == null) {
|
||||||
throw new KeyStoreConnectException();
|
throw new KeyStoreConnectException();
|
||||||
@@ -241,15 +245,59 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
|
|||||||
throw KeyStore.getKeyStoreException(opResult.resultCode);
|
throw KeyStore.getKeyStoreException(opResult.resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opResult.inputConsumed < chunk.length) {
|
if (opResult.inputConsumed <= 0) {
|
||||||
throw new IllegalStateException("Keystore failed to consume all input. Provided: "
|
// Nothing was consumed. Break out of the loop to avoid an infinite loop.
|
||||||
+ chunk.length + ", consumed: " + opResult.inputConsumed);
|
break;
|
||||||
} else if (opResult.inputConsumed > chunk.length) {
|
|
||||||
throw new IllegalStateException("Keystore consumed more input than provided"
|
|
||||||
+ " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] result = (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
|
if (opResult.inputConsumed >= chunk.length) {
|
||||||
|
// All of the input was consumed
|
||||||
|
mBuffered = EmptyArray.BYTE;
|
||||||
|
mBufferedOffset = 0;
|
||||||
|
mBufferedLength = 0;
|
||||||
|
} else {
|
||||||
|
// Some of the input was not consumed
|
||||||
|
mBuffered = chunk;
|
||||||
|
mBufferedOffset = opResult.inputConsumed;
|
||||||
|
mBufferedLength = chunk.length - opResult.inputConsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opResult.inputConsumed > chunk.length) {
|
||||||
|
throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
|
||||||
|
"Keystore consumed more input than provided. Provided: "
|
||||||
|
+ chunk.length + ", consumed: " + opResult.inputConsumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((opResult.output != null) && (opResult.output.length > 0)) {
|
||||||
|
// Some output was produced by this update operation
|
||||||
|
if (bufferedOutput == null) {
|
||||||
|
// No output buffered yet.
|
||||||
|
if (mBufferedLength == 0) {
|
||||||
|
// No more output will be produced by this flush operation
|
||||||
|
mProducedOutputSizeBytes += opResult.output.length;
|
||||||
|
return opResult.output;
|
||||||
|
} else {
|
||||||
|
// More output might be produced by this flush operation -- buffer output.
|
||||||
|
bufferedOutput = new ByteArrayOutputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Buffer the output from this update operation
|
||||||
|
try {
|
||||||
|
bufferedOutput.write(opResult.output);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ProviderException("Failed to buffer output", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBufferedLength > 0) {
|
||||||
|
throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
|
||||||
|
"Keystore failed to consume last "
|
||||||
|
+ ((mBufferedLength != 1) ? (mBufferedLength + " bytes") : "byte")
|
||||||
|
+ " of input");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = (bufferedOutput != null) ? bufferedOutput.toByteArray() : EmptyArray.BYTE;
|
||||||
mProducedOutputSizeBytes += result.length;
|
mProducedOutputSizeBytes += result.length;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user