summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java94
1 files changed, 71 insertions, 23 deletions
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index ea0f4b9..dbb79bc 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -19,12 +19,14 @@ package android.security.keystore;
import android.os.IBinder;
import android.security.KeyStore;
import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import libcore.util.EmptyArray;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.security.ProviderException;
/**
* 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;
mBufferedOffset = 0;
mBufferedLength = 0;
- } else if (opResult.inputConsumed == 0) {
+ } else if (opResult.inputConsumed <= 0) {
// Nothing was consumed. More input needed.
if (inputLength > 0) {
// More input is available, but it wasn't included into the previous chunk
// because the chunk reached its maximum permitted size.
// Shouldn't have happened.
- throw new IllegalStateException("Nothing consumed from max-sized chunk: "
- + chunk.length + " bytes");
+ throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
+ "Keystore consumed nothing from max-sized chunk: " + chunk.length
+ + " bytes");
}
mBuffered = chunk;
mBufferedOffset = 0;
@@ -153,8 +156,9 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
mBufferedOffset = opResult.inputConsumed;
mBufferedLength = chunk.length - opResult.inputConsumed;
} else {
- throw new IllegalStateException("Consumed more than provided: "
- + opResult.inputConsumed + ", provided: " + 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)) {
@@ -165,7 +169,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
try {
bufferedOutput.write(opResult.output);
} catch (IOException e) {
- throw new IllegalStateException("Failed to buffer output", e);
+ throw new ProviderException("Failed to buffer output", e);
}
}
} else {
@@ -179,7 +183,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
try {
bufferedOutput.write(opResult.output);
} catch (IOException e) {
- throw new IllegalStateException("Failed to buffer output", e);
+ throw new ProviderException("Failed to buffer output", e);
}
result = bufferedOutput.toByteArray();
}
@@ -229,27 +233,71 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
return EmptyArray.BYTE;
}
- byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
- mBuffered = EmptyArray.BYTE;
- mBufferedLength = 0;
- mBufferedOffset = 0;
+ // 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);
+ OperationResult opResult = mKeyStoreStream.update(chunk);
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeyStore.getKeyStoreException(opResult.resultCode);
+ }
- OperationResult opResult = mKeyStoreStream.update(chunk);
- if (opResult == null) {
- throw new KeyStoreConnectException();
- } else if (opResult.resultCode != KeyStore.NO_ERROR) {
- throw KeyStore.getKeyStoreException(opResult.resultCode);
+ if (opResult.inputConsumed <= 0) {
+ // Nothing was consumed. Break out of the loop to avoid an infinite loop.
+ break;
+ }
+
+ 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 (opResult.inputConsumed < chunk.length) {
- throw new IllegalStateException("Keystore failed to consume all input. Provided: "
- + chunk.length + ", consumed: " + opResult.inputConsumed);
- } else if (opResult.inputConsumed > chunk.length) {
- throw new IllegalStateException("Keystore consumed more input than provided"
- + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
+ 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 = (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
+ byte[] result = (bufferedOutput != null) ? bufferedOutput.toByteArray() : EmptyArray.BYTE;
mProducedOutputSizeBytes += result.length;
return result;
}