diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAbortOperationCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAbortOperationCmd.java deleted file mode 100644 index ee3e052a..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAbortOperationCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMAbortOperationCmd extends KMAbstractCmd { - public static final byte INS_ABORT_OPERATION_CMD = 0x22; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_ABORT_OPERATION_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAbstractCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAbstractCmd.java deleted file mode 100644 index 02fad435..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAbstractCmd.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public abstract class KMAbstractCmd implements KMCommand { - - /** - * Implements the KMCommand interface. - * - * @param context provides information required to execute the command. - */ - @Override - public void execute(KMContext context) { - // Assert the command's operational state - if (!this.validateState(context.getKeymasterState())) { - throw new KMException(KMException.CMD_NOT_ACCEPTED_WRONG_STATE); - } - KMEncoder encoder = context.getRepository().getEncoder(); - KMDecoder decoder = context.getRepository().getDecoder(); - // Get getExpectedArgs if expected - KMArray args = null; - if (hasArguments()) { - // Deserialize the getExpectedArgs - KMArray argsProto = getExpectedArgs(); - args = decoder.decode(argsProto, context.getBuffer(), (short) 0, context.getBufferLength()); - } - // Pass control to concrete command subclass - KMArray resp = this.process(args, context); - context.setBufferLength((short)0); - // If there is resp then serialize and send - if (resp != null) { - // set outgoing buffer - short len = encoder.encode(resp, context.getBuffer(), (short) 0, (short)context.getBuffer().length); - context.setBufferLength(len); - } - } - - /** - * Get the getExpectedArgs prototype expression from the concrete subclass. - * - * @return KMArray of KMType objects which provides expression for the command's getExpectedArgs.. - */ - protected abstract KMArray getExpectedArgs(); - - /** - * Implemented by the subclass to execute the command specific functionality. - * - * @param args which are decoded from the the apdu. - * @param context within which the command should be executed. - * @return Null or response having the result of the command's execution. - */ - protected abstract KMArray process(KMArray args, KMContext context); - - /** - * Validate the state required by the command to execute. By default all the commands can execute - * in active state. - * - * @param state is the current state of the applet - * @return true if the state is valid for command's execution else false is returned. - */ - protected boolean validateState(byte state) { - return (KMKeymasterApplet.ACTIVE_STATE == state); - } - - @Override - public boolean hasArguments(){ - return true; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAddRngEntropyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAddRngEntropyCmd.java deleted file mode 100644 index cb431b8f..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAddRngEntropyCmd.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -import javacard.framework.ISO7816; -import javacard.framework.JCSystem; -import javacard.framework.Util; - -// This command adds entropy into the current entropy pool as per hal specifications. -public class KMAddRngEntropyCmd extends KMAbstractCmd { - public static final byte INS_ADD_RNG_ENTROPY_CMD = 0x18; - public static final short MAX_SEED_SIZE = 2048; - - @Override - protected KMArray getExpectedArgs() { - return KMArray.instance((short) 1).add((short) 0, KMByteBlob.instance()); - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - KMByteBlob blob = (KMByteBlob) args.get((short) 0); - // maximum 2KiB of seed is allowed. - if (blob.length() > MAX_SEED_SIZE) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); - } - KMUtil.init(context.getRepository()); - // Get existing entropy pool. - byte[] entPool = context.getRepository().getEntropyPool(); - // Create new temporary pool. - byte[] heapRef = context.getRepository().getByteHeapRef(); - short poolStart = context.getRepository().newByteArray((short) entPool.length); - // Populate the new pool with the entropy which is derived from current entropy pool. - KMUtil.newRandomNumber(heapRef, poolStart, (short) entPool.length); - // Copy the entropy to the current pool - updates the entropy pool. - Util.arrayCopy(heapRef, poolStart, entPool, (short) 0, (short) entPool.length); - short index = 0; - short randIndex = 0; - // Mix (XOR) the seed received from the master in the entropy pool - 32 bytes (entPool.length). - // at a time. - while (index < blob.length()) { - entPool[randIndex] = (byte) (entPool[randIndex] ^ blob.get(index)); - randIndex++; - index++; - if (randIndex >= entPool.length) { - randIndex = 0; - } - } - // TODO return success error code. - return null; - } - - @Override - public byte getIns() { - return INS_ADD_RNG_ENTROPY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMArray.java b/Applet/Applet/src/com/android/javacard/keymaster/KMArray.java index 23b5afe6..d2eed688 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMArray.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMArray.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMArray extends KMType { private KMType[] vals; @@ -67,7 +68,7 @@ public KMArray withLength(short length) { public KMArray add(short index, KMType val) { if (index >= length) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } vals[(short) (startOff + index)] = val; return this; @@ -75,7 +76,7 @@ public KMArray add(short index, KMType val) { public KMType get(short index) { if (index >= length) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } return vals[(short) (startOff + index)]; } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestKeyCmd.java deleted file mode 100644 index 9d51e231..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestKeyCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMAttestKeyCmd extends KMAbstractCmd { - public static final byte INS_ATTEST_KEY_CMD = 0x14; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_ATTEST_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMBeginOperationCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMBeginOperationCmd.java deleted file mode 100644 index 2ab55233..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMBeginOperationCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMBeginOperationCmd extends KMAbstractCmd { - public static final byte INS_BEGIN_OPERATION_CMD = 0x1F; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_BEGIN_OPERATION_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index 6cf41894..2e088893 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMBoolTag extends KMTag { @@ -81,7 +82,7 @@ public byte getVal() { // create default assignBlob without any value public static KMBoolTag instance(short key) { if (!validateKey(key)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMBoolTag tag = repository.newBoolTag(); tag.key = key; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java index fca5b947..54b0e9e4 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; // Byte val represents contiguous memory buffer. @@ -48,7 +49,7 @@ public static KMByteBlob instance() { // copy the blob public static KMByteBlob instance(byte[] blob, short startOff, short length) { if ((length <= 0) || ((short)(startOff+length) > blob.length)) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMByteBlob inst = instance(length); Util.arrayCopyNonAtomic(blob, startOff, inst.val, inst.startOff, inst.length); @@ -58,7 +59,7 @@ public static KMByteBlob instance(byte[] blob, short startOff, short length) { // returns empty blob with given length public static KMByteBlob instance(short length) { if (length <= 0) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMByteBlob inst = instance(); inst.startOff = repository.newByteArray(length); @@ -83,20 +84,20 @@ public KMByteBlob withLength(short len) { public void add(short index, byte val) { if (index >= this.length) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (this.val == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } this.val[(short) (startOff + index)] = val; } public byte get(short index) { if (index >= this.length) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (this.val == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } return this.val[(short) (startOff + index)]; } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java index c415abbc..1569394c 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMByteTag extends KMTag { @@ -74,7 +75,7 @@ public static KMByteTag instance() { public static KMByteTag instance(short key) { if (!validateKey(key)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMByteTag tag = repository.newByteTag(); tag.key = key; @@ -93,7 +94,7 @@ public static void create(KMByteTag[] byteTagRefTable) { // create default assignBlob without any value public static KMByteTag instance(short key, KMByteBlob array) { if (!validateKey(key)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMByteTag tag = repository.newByteTag(); tag.key = key; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMCommand.java b/Applet/Applet/src/com/android/javacard/keymaster/KMCommand.java deleted file mode 100644 index 9e17dd58..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMCommand.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -import javacard.framework.APDU; - -/** This interface declares methods to be implemented by the command instances. */ -public interface KMCommand { - /** - * Execute this command within given context. If the command fails then it throws an exception - * - * @param context provides information required to execute the command. - */ - void execute(KMContext context); - - /** - * Return the instruction code associated with this command. The implementations will provide this - * code. - * - * @return instruction code which is related APDU INS. - */ - byte getIns(); - - /** - * Indicates whether command has arguments. - * @ return true if the command has arguments - */ - boolean hasArguments(); -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMComputeSharedHmacCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMComputeSharedHmacCmd.java deleted file mode 100644 index 5d2e0b46..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMComputeSharedHmacCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMComputeSharedHmacCmd extends KMAbstractCmd { - public static final byte INS_COMPUTE_SHARED_HMAC_CMD = 0x19; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_COMPUTE_SHARED_HMAC_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMContext.java b/Applet/Applet/src/com/android/javacard/keymaster/KMContext.java deleted file mode 100644 index 0d081f89..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMContext.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -/** - * This class provides data structure for information which is passed between the Keymaster Applet - * and the commands. It is created by applet and initialized for the process request. Applet sets - * repository, apdu and keymasterState. Command sets and uses incoming buffer information, outgoing - * buffer information and operation state (if command is an operation). - */ -public class KMContext { - private KMRepository repository; - private byte keymasterState; - private KMOperationState opState; - private byte[] buffer; - private short bufferLength; - /** - * Setter for the keymasterState. Set by the applet. - * - * @param keymasterState represents current applet state. - */ - public void setKeymasterState(byte keymasterState) { - this.keymasterState = keymasterState; - } - - /** - * Getter for keymasterState. Used by the commands. - * - * @return keymasterState represents current applets state. - */ - public byte getKeymasterState() { - return keymasterState; - } - - - /** - * Getter for buffer used for receiving or sending data to or from the master. Used by the - * messenger. - * - * @return buffer which is used to copying data to and from apdu's buffer. Start offset is always - * 0. - */ - public byte[] getBuffer() { - return buffer; - } - - /** - * Setter for buffer. Used by the repository. - * - * @param buffer which is used to copying data to and from apdu's buffer. - */ - public void setBuffer(byte[] buffer) { - this.buffer = buffer; - } - - /** - * Getter for buffer length. Used by the messenger and commands. - * - * @return buffer length. - */ - public short getBufferLength() { - return bufferLength; - } - - /** - * Setter for buffer length. Used by the messenger commands. - * - * @param length of buffer. - */ - public void setBufferLength(short length) { - this.bufferLength = length; - } - - /** - * Getter for repository instance. Used by commands. - * - * @return repository - */ - public KMRepository getRepository() { - return repository; - } - - /** - * Setter for the repository instance. Used by the applet. - * - * @param repository is repository of the KMType objects and other objects. - */ - public void setRepository(KMRepository repository) { - this.repository = repository; - } - - /** - * Getter for the OperationState for operation specific commands. Used by commands. - * - * @return Operation state associated with the command. - */ - public KMOperationState getOpState() { - return opState; - } - - /** Setter for the OperationState for operation specific commands. Used by commands. */ - public void setOpState(KMOperationState opState) { - this.opState = opState; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java index 4cedfcaf..a1c43aa3 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; // TODO Clean and refactor the code. public class KMDecoder { @@ -67,7 +68,7 @@ private KMIntegerArrayTag decode(KMIntegerArrayTag exp) { readTagKey(exp.getTagType()); // the values are array of integers. if (!(exp.getValues().getType() instanceof KMInteger)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } return exp.instance(this.tagKey, decode(exp.getValues(), (KMInteger) exp.getValues().getType())); } @@ -90,10 +91,10 @@ private KMBoolTag decode(KMBoolTag exp) { // BOOL Tag is a leaf node and it must always have tiny encoded uint value = 1. // TODO check this out. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } if ((byte) (buffer[startOff] & ADDITIONAL_MASK) != 0x01) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } incrementStartOff((short) 1); return exp.instance(tagKey); @@ -104,12 +105,12 @@ private KMEnumTag decode(KMEnumTag exp) { // Enum Tag value will always be integer with max 1 byte length. // TODO Check this out. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short len = (short) (buffer[startOff] & ADDITIONAL_MASK); byte enumVal = 0; if (len > UINT8_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (len < UINT8_LENGTH) { enumVal = (byte)(len & ADDITIONAL_MASK); @@ -126,12 +127,12 @@ private KMEnum decode(KMEnum exp) { // Enum value will always be integer with max 1 byte length. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short len = (short) (buffer[startOff] & ADDITIONAL_MASK); byte enumVal = 0; if (len > UINT8_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (len < UINT8_LENGTH) { enumVal = (byte)(len & ADDITIONAL_MASK); @@ -147,9 +148,12 @@ private KMEnum decode(KMEnum exp) { private KMInteger decode(KMInteger exp) { KMInteger inst; if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short len = (short) (buffer[startOff] & ADDITIONAL_MASK); + if(len > UINT64_LENGTH){ + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } incrementStartOff((short) 1); if (len < UINT8_LENGTH) { inst = exp.uint_8((byte)(len & ADDITIONAL_MASK)); @@ -162,11 +166,9 @@ private KMInteger decode(KMInteger exp) { } else if (len == UINT32_LENGTH) { inst = exp.instance(buffer, startOff, (short) 4); incrementStartOff((short) 4); - } else if (len == UINT64_LENGTH) { + } else { inst = exp.instance(buffer, startOff, (short) 8); incrementStartOff((short) 8); - } else { - throw new KMException(ISO7816.SW_WRONG_LENGTH); } return inst; } @@ -181,7 +183,7 @@ private KMByteBlob decode(KMByteBlob exp) { private KMArray decode(KMArray exp) { short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); if (exp.length() != payloadLength) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMArray inst = exp.instance(payloadLength); short index = 0; @@ -260,7 +262,7 @@ private KMType decode(KMType exp) { } if (exp instanceof KMVector) { if (!((((KMVector) exp).getType()) instanceof KMInteger)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } return decode((KMVector) exp, (KMInteger) ((KMVector) exp).getType()); } @@ -300,16 +302,17 @@ private KMType decode(KMType exp) { if (exp instanceof KMHardwareAuthToken) { return decode((KMHardwareAuthToken) exp); } - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + return null; } private short peekTagType() { if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } if ((short) (buffer[startOff] & ADDITIONAL_MASK) != UINT32_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } return (short) ((Util.makeShort(buffer[(short) (startOff + 1)], buffer[(short) (startOff + 2)])) @@ -318,16 +321,16 @@ private short peekTagType() { private void readTagKey(short expectedTagType) { if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } if ((byte) (buffer[startOff] & ADDITIONAL_MASK) != UINT32_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } incrementStartOff((short) 1); this.tagType = readShort(); this.tagKey = readShort(); if (tagType != expectedTagType) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } @@ -336,11 +339,11 @@ private short readMajorTypeWithPayloadLength(short majorType) { short payloadLength = 0; byte val = readByte(); if ((short) (val & MAJOR_TYPE_MASK) != majorType) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short lenType = (short) (val & ADDITIONAL_MASK); if (lenType > UINT16_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (lenType < UINT8_LENGTH) { payloadLength = lenType; @@ -367,7 +370,7 @@ private byte readByte() { private void incrementStartOff(short inc) { startOff += inc; if (startOff > this.length) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteAllKeysCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteAllKeysCmd.java deleted file mode 100644 index 5c476cd0..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteAllKeysCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMDeleteAllKeysCmd extends KMAbstractCmd { - public static final byte INS_DELETE_ALL_KEYS_CMD = 0x17; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_DELETE_ALL_KEYS_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteKeyCmd.java deleted file mode 100644 index ced6e7e4..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDeleteKeyCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMDeleteKeyCmd extends KMAbstractCmd { - public static final byte INS_DELETE_KEY_CMD = 0x16; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_DELETE_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDestroyAttestationIdsCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDestroyAttestationIdsCmd.java deleted file mode 100644 index fa66ab1f..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDestroyAttestationIdsCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMDestroyAttestationIdsCmd extends KMAbstractCmd { - public static final byte INS_DESTROY_ATT_IDS_CMD = 0x1A; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_DESTROY_ATT_IDS_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java index a231563b..ec736de4 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; public class KMEncoder { @@ -124,7 +125,7 @@ private void encode(KMType exp){ encode((KMHardwareAuthToken) exp); return; } - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } private void encode(KMKeyParameters obj) { @@ -288,7 +289,7 @@ private void writeByte(byte val){ private void incrementStartOff(short inc){ startOff += inc; if (startOff >= this.length) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java index 7dad1d27..441fd833 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMEnum extends KMType { private static short[] types = {HARDWARE_TYPE, KEY_FORMAT, KEY_DERIVATION_FUNCTION}; @@ -48,7 +49,7 @@ public static KMEnum instance() { public static KMEnum instance(short enumType, byte val) { KMEnum inst = repository.newEnum(); if (!validateEnum(enumType, val)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } inst.type = enumType; inst.val = val; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java index 9c76ce66..30c40bad 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMEnumArrayTag extends KMTag { @@ -84,7 +85,7 @@ public static KMEnumArrayTag instance(short key) { // check if key is valid. byte[] vals = getAllowedEnumValues(key); if (vals == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMEnumArrayTag tag = repository.newEnumArrayTag(); tag.key = key; @@ -124,7 +125,7 @@ public static KMEnumArrayTag instance(short key, KMByteBlob blob) { // validate key byte[] allowedVals = getAllowedEnumValues(key); if (allowedVals == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short byteIndex = 0; while (byteIndex < blob.length()) { @@ -138,7 +139,7 @@ public static KMEnumArrayTag instance(short key, KMByteBlob blob) { enumIndex++; } if (!validValue) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } byteIndex++; } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java index 3cfa840e..9a641425 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMEnumTag extends KMTag { @@ -60,13 +61,12 @@ public static KMEnumTag instance() { } public static KMEnumTag instance(short key) { - if (validateEnum(key, NO_VALUE)) { - KMEnumTag tag = repository.newEnumTag(); - tag.key = key; - return tag; - } else { - throw new KMException(ISO7816.SW_DATA_INVALID); + if(!validateEnum(key, NO_VALUE)){ + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } + KMEnumTag tag = repository.newEnumTag(); + tag.key = key; + return tag; } public static void create(KMEnumTag[] enumTagRefTable) { @@ -124,7 +124,7 @@ public byte getValue() { // instantiate enum tag. public static KMEnumTag instance(short key, byte val) { if (!validateEnum(key, val)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMEnumTag tag = instance(key); tag.val = val; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMException.java b/Applet/Applet/src/com/android/javacard/keymaster/KMException.java index 3e357613..3a26b047 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMException.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMException.java @@ -16,14 +16,13 @@ package com.android.javacard.keymaster; -import javacard.framework.ISOException; - -public class KMException extends ISOException { +public class KMException { // The Applet is not in a correct state in order to execute the command. public static final short CMD_NOT_ACCEPTED_WRONG_STATE = (short) 0x6901; - public KMException(short i) { - super(i); + + public static boolean handle(short reason) { + return false; } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMExportKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMExportKeyCmd.java deleted file mode 100644 index 05d28ef6..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMExportKeyCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMExportKeyCmd extends KMAbstractCmd { - public static final byte INS_EXPORT_KEY_CMD = 0x13; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_EXPORT_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMFinishOperationCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMFinishOperationCmd.java deleted file mode 100644 index 0267e4fb..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMFinishOperationCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMFinishOperationCmd extends KMAbstractCmd { - public static final byte INS_FINISH_OPERATION_CMD = 0x21; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_FINISH_OPERATION_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMGenerateKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMGenerateKeyCmd.java deleted file mode 100644 index 0c2d69d1..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMGenerateKeyCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMGenerateKeyCmd extends KMAbstractCmd { - public static final byte INS_GENERATE_KEY_CMD = 0x10; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_GENERATE_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMGetHWInfoCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMGetHWInfoCmd.java deleted file mode 100644 index 3f6cb8f8..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMGetHWInfoCmd.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMGetHWInfoCmd extends KMAbstractCmd { - public static final byte INS_GET_HW_INFO_CMD = 0x1E; - public static final byte[] JavacardKeymasterDevice = { - 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - }; - public static final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return KMArray.instance((short) 3) - .add((short) 0, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)) - .add( - (short) 1, - KMByteBlob.instance( - JavacardKeymasterDevice, (short) 0, (short) JavacardKeymasterDevice.length)) - .add((short) 2, KMByteBlob.instance(Google, (short) 0, (short) Google.length)); - } - - @Override - public byte getIns() { - return INS_GET_HW_INFO_CMD; - } - - @Override - public boolean hasArguments() { - return false; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMGetHmacSharingParametersCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMGetHmacSharingParametersCmd.java deleted file mode 100644 index 19165531..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMGetHmacSharingParametersCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMGetHmacSharingParametersCmd extends KMAbstractCmd { - public static final byte INS_GET_HMAC_SHARING_PARAM_CMD = 0x1C; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_GET_HMAC_SHARING_PARAM_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMGetKeyCharacteristicsCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMGetKeyCharacteristicsCmd.java deleted file mode 100644 index 20fef22b..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMGetKeyCharacteristicsCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMGetKeyCharacteristicsCmd extends KMAbstractCmd { - public static final byte INS_GET_KEY_CHARACTERISTICS_CMD = 0x1D; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_GET_KEY_CHARACTERISTICS_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java b/Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java index ca3c2804..9c188c67 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMHardwareAuthToken extends KMType { public static final byte CHALLENGE = 0x00; @@ -56,7 +57,7 @@ public static KMHardwareAuthToken instance() { public static KMHardwareAuthToken instance(KMArray vals) { if (vals.length() != 6) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMHardwareAuthToken inst = repository.newHwAuthToken(); inst.vals = vals; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java b/Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java index ef08696b..a1fca4d1 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMHmacSharingParameters extends KMType { public static final byte SEED = 0x00; @@ -47,7 +48,7 @@ public static KMHmacSharingParameters instance() { public static KMHmacSharingParameters instance(KMArray vals) { if (vals.length() != 2) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMHmacSharingParameters inst = repository.newHmacSharingParameters(); inst.vals = vals; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMImportKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMImportKeyCmd.java deleted file mode 100644 index 6be0d0d7..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMImportKeyCmd.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMImportKeyCmd extends KMAbstractCmd { - public static final byte INS_IMPORT_KEY_CMD = 0x11; - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_IMPORT_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMImportWrappedKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMImportWrappedKeyCmd.java deleted file mode 100644 index e9896748..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMImportWrappedKeyCmd.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMImportWrappedKeyCmd extends KMAbstractCmd { - public static final byte INS_IMPORT_WRAPPED_KEY_CMD = 0x12; - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_IMPORT_WRAPPED_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java index 19996d18..987a0858 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; // Represents 8 bit, 16 bit, 32 bit and 64 bit integers @@ -99,34 +100,35 @@ public KMInteger setValue(byte[] val) { public short getShort() { if (val == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } else if (val.length != 4) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } return Util.makeShort(val[2], val[3]); } public byte getByte() { if (val == null) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } else if (val.length != 4) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } return val[3]; } // copy the integer value from bytes public static KMInteger instance(byte[] num, short srcOff, short length) { + if(length > 8){ + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } if (length == 1) { return uint_8(num[srcOff]); } else if (length == 2) { return uint_16(Util.makeShort(num[srcOff], num[(short) (srcOff + 1)])); } else if (length == 4) { return uint_32(num, srcOff); - } else if (length == 8) { - return uint_64(num, srcOff); } else { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + return uint_64(num, srcOff); } } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java index 9c9258a2..df96e114 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMIntegerArrayTag extends KMTag { private static final short[] tags = {USER_SECURE_ID}; @@ -69,7 +70,7 @@ public KMIntegerArrayTag asUlongArray() { public static KMIntegerArrayTag instance(short key) { if (!validateKey(key)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMIntegerArrayTag tag = repository.newIntegerArrayTag(); tag.key = key; @@ -79,10 +80,10 @@ public static KMIntegerArrayTag instance(short key) { public static KMIntegerArrayTag instance(short key, KMVector val) { if (!(val.getType() instanceof KMInteger)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } if (!(validateKey(key))) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMIntegerArrayTag tag = repository.newIntegerArrayTag(); tag.key = key; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java index 00dbf256..d583f6b2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; // Implements UINT, ULONG and DATE tags. public class KMIntegerTag extends KMTag { @@ -78,7 +79,7 @@ public static KMIntegerTag instance() { public static KMIntegerTag instance(short key) { if (!validateKey(key)) { - throw new KMException(ISO7816.SW_DATA_INVALID); + ISOException.throwIt(ISO7816.SW_DATA_INVALID); } KMIntegerTag tag = repository.newIntegerTag(); tag.key = key; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java index a6b5c7fe..d4c1a9b5 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMKeyCharacteristics extends KMType { public static final byte SOFTWARE_ENFORCED = 0x00; @@ -47,7 +48,7 @@ public static KMKeyCharacteristics instance() { public static KMKeyCharacteristics instance(KMArray vals) { if (vals.length() != 2) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMKeyCharacteristics inst = repository.newKeyCharacteristics(); inst.vals = vals; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 83512f92..0ee85ff1 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -19,7 +19,10 @@ import javacard.framework.APDU; import javacard.framework.Applet; import javacard.framework.AppletEvent; +import javacard.framework.CardRuntimeException; import javacard.framework.ISO7816; +import javacard.framework.ISOException; +import javacard.framework.JCSystem; import javacard.framework.Util; import javacardx.apdu.ExtendedLength; @@ -32,29 +35,63 @@ // - remove this in future. public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { // Constants. - public static final short MAX_LENGTH = (short) 0x04ff; // TODO: make this value configurable. + private static final short MAX_LENGTH = (short) 0x1000; // TODO: make this value configurable. private static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80; - private static final byte KM_HAL_VERSION = (byte) 0x41; + private static final short KM_HAL_VERSION = (short) 0x4000; // Possible states of the applet. - public static final byte ILLEGAL_STATE = 0x00; - public static final byte INSTALL_STATE = 0x01; - public static final byte FIRST_SELECT_STATE = 0x02; - public static final byte ACTIVE_STATE = 0x03; - public static final byte INACTIVE_STATE = 0x04; - public static final byte UNINSTALLED_STATE = 0x05; + private static final byte ILLEGAL_STATE = 0x00; + private static final byte INSTALL_STATE = 0x01; + private static final byte FIRST_SELECT_STATE = 0x02; + private static final byte ACTIVE_STATE = 0x03; + private static final byte INACTIVE_STATE = 0x04; + private static final byte UNINSTALLED_STATE = 0x05; + + // Commands + private static final byte INS_GENERATE_KEY_CMD = 0x10; + private static final byte INS_IMPORT_KEY_CMD = 0x11; + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = 0x12; + private static final byte INS_EXPORT_KEY_CMD = 0x13; + private static final byte INS_ATTEST_KEY_CMD = 0x14; + private static final byte INS_UPGRADE_KEY_CMD = 0x15; + private static final byte INS_DELETE_KEY_CMD = 0x16; + private static final byte INS_DELETE_ALL_KEYS_CMD = 0x17; + private static final byte INS_ADD_RNG_ENTROPY_CMD = 0x18; + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = 0x19; + private static final byte INS_DESTROY_ATT_IDS_CMD = 0x1A; + private static final byte INS_VERIFY_AUTHORIZATION_CMD = 0x1B; + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = 0x1C; + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = 0x1D; + private static final byte INS_GET_HW_INFO_CMD = 0x1E; + private static final byte INS_BEGIN_OPERATION_CMD = 0x1F; + private static final byte INS_UPDATE_OPERATION_CMD = 0x20; + private static final byte INS_FINISH_OPERATION_CMD = 0x21; + private static final byte INS_ABORT_OPERATION_CMD = 0x22; + private static final byte INS_PROVISION_CMD = 0x23; + + // GetHwInfo information + // TODO change this to just filling the buffer + private static final byte[] JavacardKeymasterDevice = { + 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + }; + private static final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + private static final short MAX_SEED_SIZE = 2048; // State of the applet. - private byte keymasterState = ILLEGAL_STATE; + private KMEncoder encoder; + private KMDecoder decoder; private KMRepository repository; + private byte keymasterState = ILLEGAL_STATE; + private byte[] buffer; - /** - * Registers this applet. - * - * @param repo reference to the repository which manages all the NVM objects. - */ - protected KMKeymasterApplet(KMRepository repo) { - repository = repo; + /** Registers this applet. */ + protected KMKeymasterApplet() { + keymasterState = KMKeymasterApplet.INSTALL_STATE; + repository = KMRepository.instance(); + KMUtil.init(); + encoder = new KMEncoder(); + decoder = new KMDecoder(); register(); } @@ -66,11 +103,7 @@ protected KMKeymasterApplet(KMRepository repo) { * @param bLength the length in bytes of the parameter data in bArray */ public static void install(byte[] bArray, short bOffset, byte bLength) { - KMRepository repo = new KMRepository(); - // TODO: Read the configuration from the package and pass the data in initialize method. - repo.initialize(); - KMKeymasterApplet keymaster = new KMKeymasterApplet(repo); - keymaster.setKeymasterState(KMKeymasterApplet.INSTALL_STATE); + KMKeymasterApplet keymaster = new KMKeymasterApplet(); } /** @@ -80,11 +113,11 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { */ @Override public boolean select() { - repository.onSelect(); - if (getKeymasterState() == KMKeymasterApplet.INSTALL_STATE) { - setKeymasterState(KMKeymasterApplet.FIRST_SELECT_STATE); - } else if (getKeymasterState() == KMKeymasterApplet.INACTIVE_STATE) { - setKeymasterState(KMKeymasterApplet.ACTIVE_STATE); + KMRepository.instance().onSelect(); + if (keymasterState == KMKeymasterApplet.INSTALL_STATE) { + keymasterState = KMKeymasterApplet.FIRST_SELECT_STATE; + } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { + keymasterState = KMKeymasterApplet.ACTIVE_STATE; } else { return false; } @@ -94,34 +127,36 @@ public boolean select() { /** De-selects this applet. */ @Override public void deselect() { - repository.onDeselect(); - if (getKeymasterState() == KMKeymasterApplet.ACTIVE_STATE) { - setKeymasterState(KMKeymasterApplet.INACTIVE_STATE); + KMRepository.instance().onDeselect(); + if (keymasterState == KMKeymasterApplet.ACTIVE_STATE) { + keymasterState = KMKeymasterApplet.INACTIVE_STATE; } } /** Uninstalls the applet after cleaning the repository. */ @Override public void uninstall() { - repository.onUninstall(); - if (getKeymasterState() != KMKeymasterApplet.UNINSTALLED_STATE) { - setKeymasterState(KMKeymasterApplet.UNINSTALLED_STATE); + KMRepository.instance().onUninstall(); + if (keymasterState != KMKeymasterApplet.UNINSTALLED_STATE) { + keymasterState = KMKeymasterApplet.UNINSTALLED_STATE; } } /** * Processes an incoming APDU and handles it using command objects. * - * @see APDU * @param apdu the incoming APDU */ @Override public void process(APDU apdu) { - repository.onProcess(); + KMRepository.instance().onProcess(); + if (buffer == null) { + buffer = JCSystem.makeTransientByteArray(MAX_LENGTH, JCSystem.CLEAR_ON_RESET); + } // Verify whether applet is in correct state. - if ((getKeymasterState() != KMKeymasterApplet.ACTIVE_STATE) - && (getKeymasterState() != KMKeymasterApplet.FIRST_SELECT_STATE)) { - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if ((keymasterState != KMKeymasterApplet.ACTIVE_STATE) + && (keymasterState != KMKeymasterApplet.FIRST_SELECT_STATE)) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // If this is select applet apdu which is selecting this applet then return if (apdu.isISOInterindustryCLA()) { @@ -129,105 +164,295 @@ public void process(APDU apdu) { return; } } - // Read the apdu header and buffer. - byte[] buffer = apdu.getBuffer(); - byte apduClass = buffer[ISO7816.OFFSET_CLA]; - byte apduIns = buffer[ISO7816.OFFSET_INS]; - byte halVersion = buffer[ISO7816.OFFSET_P1]; - byte apduP2 = buffer[ISO7816.OFFSET_P2]; - + byte[] apduBuffer = apdu.getBuffer(); + byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; + byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; + short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); // Validate APDU Header. if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { - throw new KMException(ISO7816.SW_CLA_NOT_SUPPORTED); - } else if ((halVersion != KMKeymasterApplet.KM_HAL_VERSION) && (apduP2 != (byte) 0x00)) { - throw new KMException(ISO7816.SW_INCORRECT_P1P2); + ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); + } else if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { + ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } - - // Process the APDU. - try { - // Get the command object for specific INS from the repository. - KMCommand command = repository.getCommand(apduIns); - // Get the empty context object from the repository. - KMContext context = repository.getContext(); - // Initialize context - context.setKeymasterState(getKeymasterState()); - context.setBuffer(repository.getBuffer()); - if(command.hasArguments()){ - receiveIncoming(context, apdu); + // Validate whether INS can be supported + if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_PROVISION_CMD)) { + ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); + } + // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. + if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + if (apduIns != INS_PROVISION_CMD) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - // Execute the command. If the execution fails then an exception is thrown. - command.execute(context); - - // context has data that needs to be sent - if(context.getBufferLength() >0 ){ - sendOutgoing(context, apdu); + } + // Process the apdu + try { + // Handle the command + handle(apduIns, apdu); + } catch (CardRuntimeException exception) { + if (!(KMException.handle(exception.getReason()))) { + CardRuntimeException.throwIt(exception.getReason()); } - - // Update the Keymaster state according to the context. - setKeymasterState(context.getKeymasterState()); - } catch (KMException exception) { - // TODO: error handling for command related error. - // TODO: This should result in ISOException or exception with keymaster specific error codes + } finally { + // Reset the buffer. + Util.arrayFillNonAtomic(buffer, (short) 0, MAX_LENGTH, (byte) 0); } } - /** - * Sends a response, may be extended response, as requested by the command. - * - * @param context of current command. - */ - public void sendOutgoing(KMContext context, APDU apdu) { - // Initialize source - short srcLength = context.getBufferLength(); + /** Sends a response, may be extended response, as requested by the command. */ + private void sendOutgoing(byte[] srcBuffer, short srcLength, APDU apdu) { if (srcLength > MAX_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } // Send data - byte[] srcBuffer = context.getBuffer(); apdu.setOutgoing(); apdu.setOutgoingLength(srcLength); apdu.sendBytesLong(srcBuffer, (short) 0, srcLength); } - /** - * Receives data, which can be extended data, as requested by the command instance. - * - * @param context of current command. - */ - public void receiveIncoming(KMContext context, APDU apdu) { + /** Receives data, which can be extended data, as requested by the command instance. */ + private short receiveIncoming(byte[] destBuffer, APDU apdu) { // Initialize source byte[] srcBuffer = apdu.getBuffer(); // Initialize destination - byte[] destBuffer = context.getBuffer(); short destOffset = (short) 0; - // Receive data short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); short srcLength = apdu.getIncomingLength(); if (srcLength > MAX_LENGTH) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } while (recvLen > 0) { Util.arrayCopyNonAtomic(srcBuffer, srcOffset, destBuffer, destOffset, recvLen); destOffset += recvLen; recvLen = apdu.receiveBytes(srcOffset); } - // Update the Context - context.setBufferLength(srcLength); + return srcLength; } - /** - * Getter for keymaster state. - * - * @return keymasterState - current state of the applet. - */ - private byte getKeymasterState() { - return keymasterState; + // Commands + private void handle(byte ins, APDU apdu) { + switch (ins) { + case INS_GENERATE_KEY_CMD: + processGenerateKey(apdu); + break; + case INS_IMPORT_KEY_CMD: + processImportKeyCmd(apdu); + break; + case INS_IMPORT_WRAPPED_KEY_CMD: + processImportWrappedKeyCmd(apdu); + break; + case INS_EXPORT_KEY_CMD: + processExportKeyCmd(apdu); + break; + case INS_ATTEST_KEY_CMD: + processAttestKeyCmd(apdu); + break; + case INS_UPGRADE_KEY_CMD: + processUpgradeKeyCmd(apdu); + break; + case INS_DELETE_KEY_CMD: + processDeleteKeyCmd(apdu); + break; + case INS_DELETE_ALL_KEYS_CMD: + processDeleteAllKeysCmd(apdu); + break; + case INS_ADD_RNG_ENTROPY_CMD: + processAddRngEntropyCmd(apdu); + break; + case INS_COMPUTE_SHARED_HMAC_CMD: + processComputeSharedHmacCmd(apdu); + break; + case INS_DESTROY_ATT_IDS_CMD: + processDestroyAttIdsCmd(apdu); + break; + case INS_VERIFY_AUTHORIZATION_CMD: + processVerifyAuthenticationCmd(apdu); + break; + case INS_GET_HMAC_SHARING_PARAM_CMD: + processGetHmacSharingParamCmd(apdu); + break; + case INS_GET_KEY_CHARACTERISTICS_CMD: + processGetKeyCharacteristicsCmd(apdu); + break; + case INS_GET_HW_INFO_CMD: + processGetHwInfoCmd(apdu); + break; + case INS_BEGIN_OPERATION_CMD: + processBeginOperationCmd(apdu); + break; + case INS_UPDATE_OPERATION_CMD: + processUpdateOperationCmd(apdu); + break; + case INS_FINISH_OPERATION_CMD: + processFinishOperationCmd(apdu); + break; + case INS_ABORT_OPERATION_CMD: + processAbortOperationCmd(apdu); + break; + case INS_PROVISION_CMD: + processProvisionCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); + } } - /** Setter for keymaster state. */ - private void setKeymasterState(byte keymasterState) { - this.keymasterState = keymasterState; + + private short processProvisionCmd(APDU apdu) { + // Receive the incoming request fully from the master. + short length = receiveIncoming(buffer, apdu); + // Re-purpose the apdu buffer as scratch pad. + byte[] scratchPad = apdu.getBuffer(); + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) apdu.getBuffer().length, (byte) 0); + // Argument 1 + KMKeyParameters keyparams = KMKeyParameters.instance(); + // Argument 2 + KMEnum keyFormat = KMEnum.instance().setType(KMType.KEY_FORMAT); + // Argument 3 + KMByteBlob keyBlob = KMByteBlob.instance(); + // Array of expected arguments + KMArray argsProto = + KMArray.instance((short) 3) + .add((short) 0, keyparams) + .add((short) 1, keyFormat) + .add((short) 2, keyBlob); + // Decode the argument + KMArray args = decoder.decode(argsProto, buffer, (short) 0, length); + // TODO execute the function + // Change the state to ACTIVE + if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + keymasterState = KMKeymasterApplet.ACTIVE_STATE; + } + // nothing to return + return 0; + } + + private void processGetHwInfoCmd(APDU apdu) { + // No arguments expected + // Make the response + KMArray resp = + KMArray.instance((short) 3) + .add((short) 0, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)) + .add( + (short) 1, + KMByteBlob.instance( + JavacardKeymasterDevice, (short) 0, (short) JavacardKeymasterDevice.length)) + .add((short) 2, KMByteBlob.instance(Google, (short) 0, (short) Google.length)); + // Reuse the buffer + Util.arrayFillNonAtomic(buffer, (short) 0, MAX_LENGTH, (byte) 0); + // Encode the response + short len = encoder.encode(resp, buffer, (short) 0, MAX_LENGTH); + sendOutgoing(buffer, len, apdu); + } + + private short processAddRngEntropyCmd(APDU apdu) { + // Receive the incoming request fully from the master. + short length = receiveIncoming(buffer, apdu); + // Re-purpose the apdu buffer as scratch pad. + byte[] scratchPad = apdu.getBuffer(); + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) apdu.getBuffer().length, (byte) 0); + // Argument 1 + KMArray argsProto = KMArray.instance((short) 1).add((short) 0, KMByteBlob.instance()); + + // Decode the argument + KMArray args = decoder.decode(argsProto, buffer, (short) 0, length); + // Process + KMByteBlob blob = (KMByteBlob) args.get((short) 0); + // Maximum 2KiB of seed is allowed. + if (blob.length() > MAX_SEED_SIZE) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + // Get existing entropy pool. + byte[] entPool = KMUtil.getEntropyPool(); + // Create new temporary pool. + byte[] heapRef = repository.getByteHeapRef(); + short poolStart = repository.newByteArray((short) entPool.length); + // Populate the new pool with the entropy which is derived from current entropy pool. + KMUtil.newRandomNumber(heapRef, poolStart, (short) entPool.length); + // Copy the entropy to the current pool - updates the entropy pool. + Util.arrayCopy(heapRef, poolStart, entPool, (short) 0, (short) entPool.length); + short index = 0; + short randIndex = 0; + // Mix (XOR) the seed received from the master in the entropy pool - 32 bytes (entPool.length). + // at a time. + while (index < blob.length()) { + entPool[randIndex] = (byte) (entPool[randIndex] ^ blob.get(index)); + randIndex++; + index++; + if (randIndex >= entPool.length) { + randIndex = 0; + } + } + // Nothing to return + return 0; + } + + private short processAbortOperationCmd(APDU apdu) { + return 0; + } + + private short processFinishOperationCmd(APDU apdu) { + return 0; + } + + private short processUpdateOperationCmd(APDU apdu) { + return 0; + } + + private short processBeginOperationCmd(APDU apdu) { + return 0; + } + + private short processGetKeyCharacteristicsCmd(APDU apdu) { + return 0; + } + + private short processGetHmacSharingParamCmd(APDU apdu) { + return 0; + } + + private short processVerifyAuthenticationCmd(APDU apdu) { + return 0; + } + + private short processDestroyAttIdsCmd(APDU apdu) { + return 0; + } + + private short processComputeSharedHmacCmd(APDU apdu) { + return 0; + } + + private short processDeleteAllKeysCmd(APDU apdu) { + return 0; + } + + private short processDeleteKeyCmd(APDU apdu) { + return 0; + } + + private short processUpgradeKeyCmd(APDU apdu) { + return 0; + } + + private short processAttestKeyCmd(APDU apdu) { + return 0; + } + + private short processExportKeyCmd(APDU apdu) { + return 0; + } + + private short processImportWrappedKeyCmd(APDU apdu) { + return 0; + } + + private short processImportKeyCmd(APDU apdu) { + return 0; + } + + private short processGenerateKey(APDU apdu) { + return 0; } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMMessenger.java b/Applet/Applet/src/com/android/javacard/keymaster/KMMessenger.java deleted file mode 100644 index 3eb4b548..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMMessenger.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public interface KMMessenger { - void receiveIncoming(KMContext context); - void sendOutgoing(KMContext context); -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 5aaa9948..d1671328 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -23,12 +23,12 @@ public class KMOperationState { private KMOperationState() { operationHandle = null; } - +/* public static KMOperationState instance(KMContext context) { // TODO make operation handle return context.getRepository().newOperationState(); } - +*/ public static void create(KMOperationState[] opStateRefTable) { byte index = 0; while (index < opStateRefTable.length) { @@ -44,9 +44,11 @@ public KMInteger getOperationHandle() { public void setOperationHandle(KMInteger operationHandle) { this.operationHandle = operationHandle; } - +/* public void release(KMContext context) { // TODO release handle context.getRepository().releaseOperationState(this); } + + */ } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMProvisionCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMProvisionCmd.java deleted file mode 100644 index d1911f7e..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMProvisionCmd.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMProvisionCmd extends KMAbstractCmd { - public static final byte INS_PROVISION_CMD = 0x23; - - @Override - public byte getIns() { - return INS_PROVISION_CMD; - } - - @Override - public KMArray process(KMArray args, KMContext context) { - KMKeyParameters arg1 = (KMKeyParameters)args.get((short)0); - KMEnum arg2 = (KMEnum)args.get((short)1); - KMByteBlob arg3 = (KMByteBlob)args.get((short)2); - provision(arg1, arg2.getVal(),arg3); - context.setKeymasterState(KMKeymasterApplet.ACTIVE_STATE); - //nothing to return - return null; - } - - // TODO implement functionality - private void provision(KMKeyParameters params, byte keyFormat, KMByteBlob keyBlob){ - } - - @Override - protected boolean validateState(byte state) { - return (KMKeymasterApplet.FIRST_SELECT_STATE == state); - } - - // Uses import key command signature but does not return anything back. - protected KMArray getExpectedArgs() { - // Argument 1 - KMKeyParameters keyparams = KMKeyParameters.instance(); - // Argument 2 - KMEnum keyFormat = KMEnum.instance().setType(KMType.KEY_FORMAT); - // Argument 3 - KMByteBlob keyBlob = KMByteBlob.instance(); - // Array of expected arguments - return KMArray.instance((short) 3) - .add((short) 0, keyparams) - .add((short) 1, keyFormat) - .add((short) 2, keyBlob); - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index 36d8f6f7..b71aea01 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -27,20 +28,14 @@ // to handle onInstall and onSelect. public class KMRepository { - private static final byte CMD_TABLE_LENGTH = 20; private static final byte REF_TABLE_SIZE = 5; private static final short HEAP_SIZE = 0x1000; private static final byte INT_TABLE_SIZE = 10; private static final byte TYPE_ARRAY_SIZE = 100; private static final byte INT_SIZE = 4; private static final byte LONG_SIZE = 8; - private static final short ENTROPY_POOL_SIZE = 32; - - private KMCommand[] commandTable = null; - private KMContext context = null; - private byte[] buffer = null; + private static KMRepository repository; private AESKey masterKey = null; - private boolean contextLocked = false; private KMEncoder encoder = null; private KMDecoder decoder = null; @@ -91,38 +86,23 @@ public class KMRepository { private byte[] entropyPool = null; private byte[] counter; - public void initialize() { + public static KMRepository instance() { + if (repository == null) { + repository = new KMRepository(); + } + return repository; + } + + public KMRepository(){ + initialize(); + } + + private void initialize() { // Initialize buffers and context. JCSystem.beginTransaction(); encoder = new KMEncoder(); decoder = new KMDecoder(); - buffer = new byte[KMKeymasterApplet.MAX_LENGTH]; - context = new KMContext(); - context.setRepository(this); - contextLocked = false; operationStateTable = new KMOperationState[4]; - // Initialize command table. - commandTable = new KMCommand[CMD_TABLE_LENGTH]; - commandTable[0] = new KMProvisionCmd(); - commandTable[1] = new KMGenerateKeyCmd(); - commandTable[2] = new KMImportKeyCmd(); - commandTable[3] = new KMExportKeyCmd(); - commandTable[4] = new KMComputeSharedHmacCmd(); - commandTable[5] = new KMBeginOperationCmd(); - commandTable[6] = new KMUpdateOperationCmd(); - commandTable[7] = new KMFinishOperationCmd(); - commandTable[8] = new KMAbortOperationCmd(); - commandTable[9] = new KMVerifyAuthorizationCmd(); - commandTable[10] = new KMAddRngEntropyCmd(); - commandTable[11] = new KMImportWrappedKeyCmd(); - commandTable[12] = new KMAttestKeyCmd(); - commandTable[13] = new KMUpgradeKeyCmd(); - commandTable[14] = new KMDeleteKeyCmd(); - commandTable[15] = new KMDeleteAllKeysCmd(); - commandTable[16] = new KMDestroyAttestationIdsCmd(); - commandTable[17] = new KMGetHWInfoCmd(); - commandTable[18] = new KMGetKeyCharacteristicsCmd(); - commandTable[19] = new KMGetHmacSharingParametersCmd(); // Initialize masterkey - AES 256 bit key. if (masterKey == null) { masterKey = @@ -176,8 +156,6 @@ public void initialize() { uint64Array[index] = new byte[LONG_SIZE]; index++; } - entropyPool = new byte[ENTROPY_POOL_SIZE]; - counter = new byte[8]; JCSystem.commitTransaction(); } @@ -190,26 +168,6 @@ public KMDecoder getDecoder() { return decoder; } - public KMCommand getCommand(byte ins) throws KMException { - short cmdIndex = 0; - while (cmdIndex < CMD_TABLE_LENGTH) { - if (commandTable[cmdIndex].getIns() == ins) { - return commandTable[cmdIndex]; - } - cmdIndex++; - } - throw new KMException(ISO7816.SW_INS_NOT_SUPPORTED); - } - - public KMContext getContext() throws KMException { - if (!contextLocked) { - contextLocked = true; - return context; - } else { - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } - } - public void onUninstall() { masterKey = null; } @@ -219,11 +177,8 @@ public void onProcess() { } private void reset() { - contextLocked = false; - Util.arrayFillNonAtomic(buffer, (short) 0, (short) buffer.length, (byte) 0); - Util.arrayFillNonAtomic(byteHeap, (short) 0, (short) buffer.length, (byte) 0); + Util.arrayFillNonAtomic(byteHeap, (short) 0, (short) byteHeap.length, (byte) 0); byteHeapIndex = 0; - Util.arrayFillNonAtomic(buffer, (short) 0, (short) buffer.length, (byte) 0); short index = 0; while (index < typeRefTable.length) { typeRefTable[index] = null; @@ -285,10 +240,6 @@ public void onSelect() { // Nothing to be done currently. } - public byte[] getBuffer() { - return buffer; - } - public AESKey getMasterKey() { return masterKey; } @@ -298,7 +249,7 @@ public byte[] newIntegerArray(short length) { if (length == 4) { if (uint32Index >= uint32Array.length) { // TODO this is placeholder exception value. This needs to be replaced by 910E, 91A1 or 9210 - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } byte[] ret = (byte[]) uint32Array[uint32Index]; uint32Index++; @@ -306,20 +257,21 @@ public byte[] newIntegerArray(short length) { } else if (length == 8) { if (uint64Index >= uint64Array.length) { // TODO this is placeholder exception value. This needs to be replaced by 910E, 91A1 or 9210 - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } byte[] ret = (byte[]) uint64Array[uint64Index]; uint64Index++; return ret; } else { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } + return null;// this will never be executed. } public KMByteBlob newByteBlob() { if (blobRefIndex >= byteBlobRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMByteBlob ret = byteBlobRefTable[blobRefIndex]; blobRefIndex++; @@ -329,7 +281,7 @@ public KMByteBlob newByteBlob() { public KMInteger newInteger() { if (intRefIndex >= integerRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMInteger ret = integerRefTable[intRefIndex]; intRefIndex++; @@ -339,7 +291,7 @@ public KMInteger newInteger() { public KMEnumTag newEnumTag() { if (enumTagRefIndex >= enumTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMEnumTag ret = enumTagRefTable[enumTagRefIndex]; enumTagRefIndex++; @@ -349,7 +301,7 @@ public KMEnumTag newEnumTag() { public KMEnumArrayTag newEnumArrayTag() { if (enumArrayTagRefIndex >= enumArrayTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMEnumArrayTag ret = enumArrayTagRefTable[enumArrayTagRefIndex]; enumArrayTagRefIndex++; @@ -359,7 +311,7 @@ public KMEnumArrayTag newEnumArrayTag() { public KMIntegerTag newIntegerTag() { if (intTagRefIndex >= intTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMIntegerTag ret = intTagRefTable[intTagRefIndex]; intTagRefIndex++; @@ -369,7 +321,7 @@ public KMIntegerTag newIntegerTag() { public KMIntegerArrayTag newIntegerArrayTag() { if (intArrayTagRefIndex >= intArrayTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMIntegerArrayTag ret = intArrayTagRefTable[intArrayTagRefIndex]; intArrayTagRefIndex++; @@ -379,7 +331,7 @@ public KMIntegerArrayTag newIntegerArrayTag() { public KMBoolTag newBoolTag() { if (boolTagRefIndex >= boolTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMBoolTag ret = boolTagRefTable[boolTagRefIndex]; boolTagRefIndex++; @@ -389,7 +341,7 @@ public KMBoolTag newBoolTag() { public KMByteTag newByteTag() { if (byteTagRefIndex >= byteTagRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMByteTag ret = byteTagRefTable[byteTagRefIndex]; byteTagRefIndex++; @@ -399,7 +351,7 @@ public KMByteTag newByteTag() { public KMKeyParameters newKeyParameters() { if (keyParametersRefIndex >= keyParametersRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMKeyParameters ret = keyParametersRefTable[keyParametersRefIndex]; keyParametersRefIndex++; @@ -409,7 +361,7 @@ public KMKeyParameters newKeyParameters() { public KMArray newArray() { if (arrayRefIndex >= arrayRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMArray ret = arrayRefTable[arrayRefIndex]; arrayRefIndex++; @@ -419,7 +371,7 @@ public KMArray newArray() { public KMKeyCharacteristics newKeyCharacteristics() { if (keyCharRefIndex >= keyCharRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMKeyCharacteristics ret = keyCharRefTable[keyCharRefIndex]; keyCharRefIndex++; @@ -429,7 +381,7 @@ public KMKeyCharacteristics newKeyCharacteristics() { public KMHardwareAuthToken newHwAuthToken() { if (hwAuthTokenRefIndex >= hwAuthTokenRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMHardwareAuthToken ret = hwAuthTokenRefTable[hwAuthTokenRefIndex]; hwAuthTokenRefIndex++; @@ -439,7 +391,7 @@ public KMHardwareAuthToken newHwAuthToken() { public KMHmacSharingParameters newHmacSharingParameters() { if (hmacSharingParamsRefIndex >= hmacSharingParamsRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMHmacSharingParameters ret = hmacSharingParamsRefTable[hmacSharingParamsRefIndex]; hmacSharingParamsRefIndex++; @@ -449,7 +401,7 @@ public KMHmacSharingParameters newHmacSharingParameters() { public KMVerificationToken newVerificationToken() { if (verTokenRefIndex >= verTokenRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMVerificationToken ret = verTokenRefTable[verTokenRefIndex]; verTokenRefIndex++; @@ -459,7 +411,7 @@ public KMVerificationToken newVerificationToken() { public KMOperationState newOperationState() { if (opStateRefIndex >= opStateRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMOperationState ret = operationStateTable[opStateRefIndex]; opStateRefIndex++; @@ -469,14 +421,14 @@ public KMOperationState newOperationState() { public void releaseOperationState(KMOperationState state){ opStateRefIndex--; if(opStateRefIndex <0){ - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } opStateRefTable[opStateRefIndex] = state; } public KMVector newVector() { if (vectorRefIndex >= vectorRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMVector ret = vectorRefTable[vectorRefIndex]; vectorRefIndex++; @@ -486,7 +438,7 @@ public KMVector newVector() { public KMEnum newEnum() { if (enumRefIndex >= enumRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } KMEnum ret = enumRefTable[enumRefIndex]; enumRefIndex++; @@ -504,7 +456,7 @@ public byte[] getByteHeapRef(){ public short newTypeArray(short length) { if (((short) (typeRefIndex + length)) >= typeRefTable.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } typeRefIndex += length; return (short) (typeRefIndex - length); @@ -513,13 +465,9 @@ public short newTypeArray(short length) { public short newByteArray(short length) { if (((short) (byteHeapIndex + length)) >= byteHeap.length) { // TODO this is placeholder exception value. - throw new KMException(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } byteHeapIndex += length; return (short) (byteHeapIndex - length); } - - public byte[] getEntropyPool() { - return entropyPool; - } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMUpdateOperationCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMUpdateOperationCmd.java deleted file mode 100644 index 5b1e58f6..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMUpdateOperationCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMUpdateOperationCmd extends KMAbstractCmd { - public static final byte INS_UPDATE_OPERATION_CMD = 0x20; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_UPDATE_OPERATION_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradeKeyCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradeKeyCmd.java deleted file mode 100644 index d883068f..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradeKeyCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMUpgradeKeyCmd extends KMAbstractCmd { - public static final byte INS_UPGRADE_KEY_CMD = 0x15; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_UPGRADE_KEY_CMD; - } -} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMUtil.java b/Applet/Applet/src/com/android/javacard/keymaster/KMUtil.java index 5b42ae9d..0d1080df 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMUtil.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMUtil.java @@ -1,6 +1,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.Util; import javacard.security.AESKey; import javacard.security.CryptoException; @@ -9,27 +10,25 @@ import javacardx.crypto.Cipher; public class KMUtil { + private static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte AES_BLOCK_SIZE = 16; - private static KMRepository repository = null; + public static final byte[] aesICV = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private static byte[] counter; - private static boolean initialized = false; private static AESKey aesKey; - private static Cipher aesEcb; - - public static void init(KMRepository repo) { - if (!initialized) { - KMUtil.repository = repo; - counter = repo.newIntegerArray((short) 8); - KMUtil.initEntropyPool(repo.getEntropyPool()); + private static Cipher aesCbc; + private static byte[] entropyPool; + public static void init() { + entropyPool = new byte[ENTROPY_POOL_SIZE]; + counter = KMRepository.instance().newIntegerArray((short) 8); + KMUtil.initEntropyPool(entropyPool); try { - aesEcb = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false); + //Note: ALG_AES_BLOCK_128_CBC_NOPAD not supported by simulator. + aesCbc = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); } catch (CryptoException exp) { // TODO change this to proper error code - throw new KMException(ISO7816.SW_UNKNOWN); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); - initialized = true; - } + aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); } public static void initEntropyPool(byte[] pool) { @@ -40,26 +39,31 @@ public static void initEntropyPool(byte[] pool) { } try { trng = RandomData.getInstance(RandomData.ALG_TRNG); + trng.nextBytes(pool, (short) 0, (short) pool.length); } catch (CryptoException exp) { if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { //TODO change this when possible // simulator does not support TRNG algorithm. So, PRNG algorithm (deprecated) is used. trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); + trng.nextBytes(pool, (short) 0, (short) pool.length); } else { // TODO change this to proper error code - throw new KMException(ISO7816.SW_UNKNOWN); + ISOException.throwIt(ISO7816.SW_UNKNOWN); } } - trng.nextBytes(pool, (short) 0, (short) pool.length); + } // Generate a secure random number from existing entropy pool. This uses aes ecb algorithm with // 8 byte counter and 16 byte block size. public static void newRandomNumber(byte[] num, short startOff, short length) { + KMRepository repository = KMRepository.instance(); byte[] bufPtr = repository.getByteHeapRef(); short countBufInd = repository.newByteArray(AES_BLOCK_SIZE); short randBufInd = repository.newByteArray(AES_BLOCK_SIZE); short len = AES_BLOCK_SIZE; + aesKey.setKey(entropyPool, (short) 0); + aesCbc.init(aesKey, Cipher.MODE_ENCRYPT, aesICV, (short)0, (short)16); while (length > 0) { if (length < len ) len = length; // increment counter by one @@ -67,9 +71,7 @@ public static void newRandomNumber(byte[] num, short startOff, short length) { // copy the 8 byte counter into the 16 byte counter buffer. Util.arrayCopy(counter, (short) 0, bufPtr, countBufInd, (short) counter.length); // encrypt the counter buffer with existing entropy which forms the aes key. - aesKey.setKey(repository.getEntropyPool(), (short) 0); - aesEcb.init(aesKey, Cipher.MODE_ENCRYPT); - aesEcb.doFinal(bufPtr, countBufInd, AES_BLOCK_SIZE, bufPtr, randBufInd); + aesCbc.doFinal(bufPtr, countBufInd, AES_BLOCK_SIZE, bufPtr, randBufInd); // copy the encrypted counter block to buffer passed in the argument Util.arrayCopy(bufPtr, randBufInd, num, startOff, len); length = (short) (length - len); @@ -98,4 +100,9 @@ private static void incrementCounter() { } } } + + public static byte[] getEntropyPool() { + return entropyPool; + } + } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java b/Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java index f52fae55..d47c80e2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java @@ -17,6 +17,7 @@ package com.android.javacard.keymaster; import javacard.framework.ISO7816; +import javacard.framework.ISOException; public class KMVerificationToken extends KMType { public static final byte CHALLENGE = 0x00; @@ -61,7 +62,7 @@ public static KMVerificationToken instance() { public static KMVerificationToken instance(KMArray vals) { if (vals.length() != 5) { - throw new KMException(ISO7816.SW_WRONG_LENGTH); + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } KMVerificationToken inst = repository.newVerificationToken(); inst.vals = vals; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMVerifyAuthorizationCmd.java b/Applet/Applet/src/com/android/javacard/keymaster/KMVerifyAuthorizationCmd.java deleted file mode 100644 index 33289b44..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMVerifyAuthorizationCmd.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -public class KMVerifyAuthorizationCmd extends KMAbstractCmd { - public static final byte INS_VERIFY_AUTHORIZATION_CMD = 0x1B; - - @Override - protected KMArray getExpectedArgs() { - return null; - } - - @Override - protected KMArray process(KMArray args, KMContext context) { - return null; - } - - @Override - public byte getIns() { - return INS_VERIFY_AUTHORIZATION_CMD; - } -} diff --git a/HAL/keymaster/4.1/CborConverter.cpp b/HAL/keymaster/4.1/CborConverter.cpp new file mode 100644 index 00000000..1d22b6e8 --- /dev/null +++ b/HAL/keymaster/4.1/CborConverter.cpp @@ -0,0 +1,399 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include +#include + +bool CborConverter::addKeyparameters(Array& array, const android::hardware::hidl_vec& keyParams) { + Map map; + std::map> enum_repetition; + std::map uint_repetition; + for(size_t i = 0; i < keyParams.size(); i++) { + KeyParameter param = keyParams[i]; + TagType tagType = static_cast(param.tag & (0xF << 28)); + switch(tagType) { + case TagType::ENUM: + case TagType::UINT: + map.add(static_cast(param.tag), param.f.integer); + break; + case TagType::UINT_REP: + uint_repetition[static_cast(param.tag)].add(param.f.integer); + break; + case TagType::ENUM_REP: + enum_repetition[static_cast(param.tag)].push_back(static_cast(param.f.integer)); + break; + case TagType::ULONG: + map.add(static_cast(param.tag), param.f.longInteger); + break; + case TagType::ULONG_REP: + uint_repetition[static_cast(param.tag)].add(param.f.longInteger); + break; + case TagType::DATE: + map.add(static_cast(param.tag), param.f.dateTime); + break; + case TagType::BOOL: + map.add(static_cast(param.tag), static_cast(param.f.boolValue)); + break; + case TagType::BIGNUM: + case TagType::BYTES: + map.add(static_cast(param.tag), (std::vector(param.blob))); + break; + default: + /* Invalid skip */ + break; + } + } + if(0 < enum_repetition.size()) { + for( auto const& [key, val] : enum_repetition ) { + Bstr bstr(val); + map.add(key, std::move(bstr)); + } + } + if(0 < uint_repetition.size()) { + for( auto & [key, val] : uint_repetition ) { + map.add(key, std::move(val)); + } + } + array.add(std::move(map)); + return true; +} + +bool CborConverter::getKeyCharacteristics(const std::unique_ptr &item, const uint32_t pos, + KeyCharacteristics& keyCharacteristics) { + bool ret = false; + std::unique_ptr arrayItem(nullptr); + getItemAtPos(item, pos, arrayItem); + if ((arrayItem == nullptr) || (MajorType::ARRAY != getType(arrayItem))) + return ret; + + if (!getKeyParameters(arrayItem, 0, keyCharacteristics.softwareEnforced)) { + return ret; + } + + if (!getKeyParameters(arrayItem, 1, keyCharacteristics.hardwareEnforced)) { + return ret; + } + //success + ret = true; + return ret; +} + +bool CborConverter::getKeyParameter(const std::pair&, + const std::unique_ptr&> pair, std::vector& keyParams) { + bool ret = false; + uint64_t key; + uint64_t value; + + if(!getUint64(pair.first, key)) { + return ret; + } + + /* Get the TagType from the Tag */ + TagType tagType = static_cast(key & (0xF << 28)); + switch(tagType) { + case TagType::ENUM_REP: + { + /* ENUM_REP contains values encoded in a Binary string */ + const Bstr* bstr = pair.second.get()->asBstr(); + if(bstr == nullptr) return ret; + for (auto bchar : bstr->value()) { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + keyParam.f.integer = bchar; + keyParams.push_back(std::move(keyParam)); + } + return true; + } + break; + case TagType::ENUM: + case TagType::UINT: + { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + if(!getUint64(pair.second, value)) { + return ret; + } + keyParam.f.integer = static_cast(value); + keyParams.push_back(std::move(keyParam)); + return true; + } + break; + case TagType::ULONG: + { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + if(!getUint64(pair.second, value)) { + return ret; + } + keyParam.f.longInteger = value; + keyParams.push_back(std::move(keyParam)); + return true; + } + break; + case TagType::UINT_REP: + { + /* UINT_REP contains values encoded in a Array */ + Array* array = const_cast(pair.second.get()->asArray()); + if(array == nullptr) return ret; + for(int i = 0; i < array->size(); i++) { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + std::unique_ptr item = std::move((*array)[i]); + if(!getUint64(item, value)) { + return ret; + } + keyParam.f.integer = static_cast(value); + keyParams.push_back(std::move(keyParam)); + + } + return true; + } + break; + case TagType::ULONG_REP: + { + /* ULONG_REP contains values encoded in a Array */ + Array* array = const_cast(pair.second.get()->asArray()); + if(array == nullptr) return ret; + for(int i = 0; i < array->size(); i++) { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + std::unique_ptr item = std::move((*array)[i]); + if(!getUint64(item, keyParam.f.longInteger)) { + return ret; + } + keyParams.push_back(std::move(keyParam)); + + } + return true; + } + break; + case TagType::DATE: + { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + if(!getUint64(pair.second, value)) { + return ret; + } + keyParam.f.dateTime = value; + keyParams.push_back(std::move(keyParam)); + return true; + } + break; + case TagType::BOOL: + { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + if(!getUint64(pair.second, value)) { + return ret; + } + keyParam.f.boolValue = static_cast(value); + keyParams.push_back(std::move(keyParam)); + return true; + } + break; + case TagType::BYTES: + { + KeyParameter keyParam; + keyParam.tag = static_cast(key); + const Bstr* bstr = pair.second.get()->asBstr(); + if(bstr == nullptr) return ret; + keyParam.blob = bstr->value(); + keyParams.push_back(std::move(keyParam)); + return true; + } + break; + default: + /* Invalid skip */ + break; + } + return ret; +} + + +bool CborConverter::getMultiBinaryArray(const std::unique_ptr& item, const uint32_t pos, + std::vector>& data) { + bool ret = false; + std::unique_ptr arrayItem(nullptr); + + getItemAtPos(item, pos, arrayItem); + if ((arrayItem == nullptr) || (MajorType::ARRAY != getType(arrayItem))) + return ret; + const Array* arr = arrayItem.get()->asArray(); + size_t arrSize = arr->size(); + for (int i = 0; i < arrSize; i++) { + std::vector temp; + if (!getBinaryArray(arrayItem, i, temp)) + return ret; + data.push_back(std::move(temp)); + } + ret = true; // success + return ret; +} + +bool CborConverter::getBinaryArray(const std::unique_ptr& item, const uint32_t pos, +::android::hardware::hidl_vec& value) { + bool ret = false; + std::unique_ptr strItem(nullptr); + getItemAtPos(item, pos, strItem); + if ((strItem == nullptr) || (MajorType::BSTR != getType(strItem))) + return ret; + + const Bstr* bstr = strItem.get()->asBstr(); + value = bstr->value(); + ret = true; + return ret; +} + + +bool CborConverter::getBinaryArray(const std::unique_ptr& item, const uint32_t pos, std::vector& value) { + bool ret = false; + std::unique_ptr strItem(nullptr); + getItemAtPos(item, pos, strItem); + if ((strItem == nullptr) || (MajorType::BSTR != getType(strItem))) + return ret; + + const Bstr* bstr = strItem.get()->asBstr(); + for (auto bchar : bstr->value()) { + value.push_back(bchar); + } + ret = true; + return ret; +} + +bool CborConverter::getHmacSharingParameters(const std::unique_ptr& item, const uint32_t pos, HmacSharingParameters& params) { + std::vector paramValue; + bool ret = false; + std::unique_ptr arrayItem(nullptr); + + //1. Get ArrayItem + //2. First item in the array seed; second item in the array is nonce. + + getItemAtPos(item, pos, arrayItem); + if ((arrayItem == nullptr) || (MajorType::ARRAY != getType(arrayItem))) + return ret; + + //Seed + if (!getBinaryArray(arrayItem, 0, params.seed)) + return ret; + + //nonce + if (!getBinaryArray(arrayItem, 1, paramValue)) + return ret; + memcpy(params.nonce.data(), paramValue.data(), paramValue.size()); + ret = true; + return ret; +} + +bool CborConverter::addVerificationToken(Array& array, const VerificationToken& + verificationToken, std::vector& encodedParamsVerified) { + Array vToken; + vToken.add(verificationToken.challenge); + vToken.add(verificationToken.timestamp); + vToken.add(std::move(encodedParamsVerified)); + vToken.add(static_cast(verificationToken.securityLevel)); + vToken.add((std::vector(verificationToken.mac))); + array.add(std::move(vToken)); + return true; +} + +bool CborConverter::addHardwareAuthToken(Array& array, const HardwareAuthToken& + authToken) { + Array hwAuthToken; + hwAuthToken.add(authToken.challenge); + hwAuthToken.add(authToken.userId); + hwAuthToken.add(authToken.authenticatorId); + hwAuthToken.add(static_cast(authToken.authenticatorType)); + hwAuthToken.add(authToken.timestamp); + hwAuthToken.add((std::vector(authToken.mac))); + array.add(std::move(hwAuthToken)); + return true; +} + +bool CborConverter::getHardwareAuthToken(const std::unique_ptr& item, const uint32_t pos, HardwareAuthToken& token) { + bool ret = false; + //challenge + if (!getUint64(item, pos, token.challenge)) + return ret; + //userId + if (!getUint64(item, pos+1, token.userId)) + return ret; + //AuthenticatorId + if (!getUint64(item, pos+2, token.authenticatorId)) + return ret; + //AuthType + uint64_t authType; + if (!getUint64(item, pos+3, authType)) + return ret; + token.authenticatorType = static_cast(authType); + //Timestamp + if (!getUint64(item, pos+4, token.timestamp)) + return ret; + //MAC + if (!getBinaryArray(item, pos+5, token.mac)) + return ret; + ret = true; + return ret; +} + +bool CborConverter::getVerificationToken(const std::unique_ptr& item, const uint32_t pos, VerificationToken& + token) { + bool ret = false; + //challenge + if (!getUint64(item, pos, token.challenge)) + return ret; + + //timestamp + if (!getUint64(item, pos+1, token.timestamp)) + return ret; + + //List of KeyParameters + if (!getKeyParameters(item, pos+2, token.parametersVerified)) + return ret; + + //AuthenticatorId + uint64_t val; + if (!getUint64(item, pos+3, val)) + return ret; + token.securityLevel = static_cast(val); + + //MAC + if (!getBinaryArray(item, pos+4, token.mac)) + return ret; + ret = true; + return ret; + +} + +bool CborConverter::getKeyParameters(const std::unique_ptr& item, const uint32_t pos, android::hardware::hidl_vec& keyParams) { + bool ret = false; + std::unique_ptr mapItem(nullptr); + std::vector params; + getItemAtPos(item, pos, mapItem); + if ((mapItem == nullptr) || (MajorType::MAP != getType(mapItem))) + return ret; + const Map* map = mapItem.get()->asMap(); + size_t mapSize = map->size(); + for (int i = 0; i < mapSize; i++) { + if (!getKeyParameter((*map)[i], params)) { + return ret; + } + } + keyParams.resize(params.size()); + keyParams = params; + ret = true; + return ret; +} diff --git a/HAL/keymaster/4.1/CommonUtils.cpp b/HAL/keymaster/4.1/CommonUtils.cpp new file mode 100644 index 00000000..67993957 --- /dev/null +++ b/HAL/keymaster/4.1/CommonUtils.cpp @@ -0,0 +1,228 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +hidl_vec kmParamSet2Hidl(const keymaster_key_param_set_t& set) { + hidl_vec result; + if (set.length == 0 || set.params == nullptr) + return result; + + result.resize(set.length); + keymaster_key_param_t* params = set.params; + for (size_t i = 0; i < set.length; ++i) { + auto tag = params[i].tag; + result[i].tag = legacy_enum_conversion(tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + result[i].f.integer = params[i].enumerated; + break; + case KM_UINT: + case KM_UINT_REP: + result[i].f.integer = params[i].integer; + break; + case KM_ULONG: + case KM_ULONG_REP: + result[i].f.longInteger = params[i].long_integer; + break; + case KM_DATE: + result[i].f.dateTime = params[i].date_time; + break; + case KM_BOOL: + result[i].f.boolValue = params[i].boolean; + break; + case KM_BIGNUM: + case KM_BYTES: + result[i].blob.setToExternal(const_cast(params[i].blob.data), + params[i].blob.data_length); + break; + case KM_INVALID: + default: + params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + return result; +} + +keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec& keyParams) { + keymaster_key_param_set_t set; + + set.params = new keymaster_key_param_t[keyParams.size()]; + set.length = keyParams.size(); + + for (size_t i = 0; i < keyParams.size(); ++i) { + auto tag = legacy_enum_conversion(keyParams[i].tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + set.params[i] = keymaster_param_enum(tag, keyParams[i].f.integer); + break; + case KM_UINT: + case KM_UINT_REP: + set.params[i] = keymaster_param_int(tag, keyParams[i].f.integer); + break; + case KM_ULONG: + case KM_ULONG_REP: + set.params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger); + break; + case KM_DATE: + set.params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime); + break; + case KM_BOOL: + if (keyParams[i].f.boolValue) + set.params[i] = keymaster_param_bool(tag); + else + set.params[i].tag = KM_TAG_INVALID; + break; + case KM_BIGNUM: + case KM_BYTES: + set.params[i] = + keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size()); + break; + case KM_INVALID: + default: + set.params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + + return set; +} + +ErrorCode getEcCurve(const EC_GROUP *group, EcCurve& ecCurve) { + int curve = EC_GROUP_get_curve_name(group); + switch(curve) { + case NID_secp224r1: + ecCurve = EcCurve::P_224; + break; + case NID_X9_62_prime256v1: + ecCurve = EcCurve::P_256; + break; + case NID_secp384r1: + ecCurve = EcCurve::P_384; + break; + case NID_secp521r1: + ecCurve = EcCurve::P_521; + break; + default: + return ErrorCode::UNSUPPORTED_EC_CURVE; + } + return ErrorCode::OK; +} + +ErrorCode ecRawKeyFromPKCS8(const std::vector& pkcs8Blob, std::vector& secret, std::vector& +publicKey, EcCurve& ecCurve) { + ErrorCode errorCode = ErrorCode::INVALID_KEY_BLOB; + EVP_PKEY *pkey = nullptr; + const uint8_t *data = pkcs8Blob.data(); + + d2i_PrivateKey(EVP_PKEY_EC, &pkey, &data, pkcs8Blob.size()); + if(!pkey) { + return legacy_enum_conversion(TranslateLastOpenSslError()); + } + + UniquePtr ec_key(EVP_PKEY_get1_EC_KEY(pkey)); + if(!ec_key.get()) + return legacy_enum_conversion(TranslateLastOpenSslError()); + + //Get EC Group + const EC_GROUP *group = EC_KEY_get0_group(ec_key.get()); + if(group == NULL) + return errorCode; + + if(ErrorCode::OK != (errorCode = getEcCurve(group, ecCurve))) { + return errorCode; + } + + //Extract private key. + const BIGNUM *privBn = EC_KEY_get0_private_key(ec_key.get()); + int privKeyLen = BN_num_bytes(privBn); + std::unique_ptr privKey(new uint8_t[privKeyLen]); + BN_bn2bin(privBn, privKey.get()); + secret.insert(secret.begin(), privKey.get(), privKey.get()+privKeyLen); + + //Extract public key. + const EC_POINT *point = EC_KEY_get0_public_key(ec_key.get()); + int pubKeyLen=0; + pubKeyLen = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + std::unique_ptr pubKey(new uint8_t[pubKeyLen]); + EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, pubKey.get(), pubKeyLen, NULL); + publicKey.insert(publicKey.begin(), pubKey.get(), pubKey.get()+pubKeyLen); + + EVP_PKEY_free(pkey); + return ErrorCode::OK; +} + +ErrorCode rsaRawKeyFromPKCS8(const std::vector& pkcs8Blob, std::vector& privateExp, std::vector& +pubModulus) { + ErrorCode errorCode = ErrorCode::INVALID_KEY_BLOB; + const BIGNUM *n=NULL, *e=NULL, *d=NULL; + EVP_PKEY *pkey = nullptr; + const uint8_t *data = pkcs8Blob.data(); + + d2i_PrivateKey(EVP_PKEY_RSA, &pkey, &data, pkcs8Blob.size()); + if(!pkey) { + return legacy_enum_conversion(TranslateLastOpenSslError()); + } + + UniquePtr rsa_key(EVP_PKEY_get1_RSA(pkey)); + if(!rsa_key.get()) { + return legacy_enum_conversion(TranslateLastOpenSslError()); + } + + RSA_get0_key(rsa_key.get(), &n, &e, &d); + if(d != NULL && n != NULL) { + /*private exponent */ + int privExpLen = BN_num_bytes(d); + std::unique_ptr privExp(new uint8_t[privExpLen]); + BN_bn2bin(d, privExp.get()); + /* public modulus */ + int pubModLen = BN_num_bytes(n); + std::unique_ptr pubMod(new uint8_t[pubModLen]); + BN_bn2bin(n, pubMod.get()); + + privateExp.insert(privateExp.begin(), privExp.get(), privExp.get()+privExpLen); + pubModulus.insert(pubModulus.begin(), pubMod.get(), pubMod.get()+pubModLen); + } else { + return errorCode; + } + EVP_PKEY_free(pkey); + return ErrorCode::OK; +} + + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp new file mode 100644 index 00000000..7e04681a --- /dev/null +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -0,0 +1,1114 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define APDU_CLS 0x80 +#define APDU_P1 0x40 +#define APDU_P2 0x00 +#define APDU_RESP_STATUS_OK 0x9000 +#define ROOT_RSA_KEY "/data/data/rsa_key.der" +#define ROOT_RSA_CERT "/data/data/certificate_rsa.der" +/*This property is used to check if javacard is already provisioned or not */ +#define KM_JAVACARD_PROVISIONED_PROPERTY "keymaster.javacard.provisioned" + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +static std::unique_ptr pTransportFactory = nullptr; +constexpr size_t kOperationTableSize = 16; + +struct KM_AUTH_LIST_Delete { + void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } +}; + +enum class Instruction { + INS_GENERATE_KEY_CMD = 0x10, + INS_IMPORT_KEY_CMD = 0x11, + INS_IMPORT_WRAPPED_KEY_CMD = 0x12, + INS_EXPORT_KEY_CMD = 0x13, + INS_ATTEST_KEY_CMD = 0x14, + INS_UPGRADE_KEY_CMD = 0x15, + INS_DELETE_KEY_CMD = 0x16, + INS_DELETE_ALL_KEYS_CMD = 0x17, + INS_ADD_RNG_ENTROPY_CMD = 0x18, + INS_COMPUTE_SHARED_HMAC_CMD = 0x19, + INS_DESTROY_ATT_IDS_CMD = 0x1A, + INS_VERIFY_AUTHORIZATION_CMD = 0x1B, + INS_GET_HMAC_SHARING_PARAM_CMD = 0x1C, + INS_GET_KEY_CHARACTERISTICS_CMD = 0x1D, + INS_GET_HW_INFO_CMD = 0x1E, + INS_BEGIN_OPERATION_CMD = 0x1F, + INS_UPDATE_OPERATION_CMD = 0x20, + INS_FINISH_OPERATION_CMD = 0x21, + INS_ABORT_OPERATION_CMD = 0x22, + INS_PROVISION_CMD = 0x23, + INS_SET_BOOT_PARAMS_CMD = 0x24, + INS_DEVICE_LOCKED_CMD = 0x25, + INS_EARLY_BOOT_ENDED_CMD = 0x26, +}; + +static inline std::unique_ptr& getTransportFactoryInstance() { + if(pTransportFactory == nullptr) { + pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( + android::base::GetBoolProperty("ro.kernel.qemu", false))); + pTransportFactory->openConnection(); + } + return pTransportFactory; +} + +ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector asn1ParamsVerified) { + if (verificationToken.parametersVerified.size() > 0) { + AuthorizationSet paramSet; + KeymasterBlob derBlob; + UniquePtr kmAuthList(KM_AUTH_LIST_new()); + + paramSet.Reinitialize(KmParamSet(verificationToken.parametersVerified)); + + auto err = build_auth_list(paramSet, kmAuthList.get()); + if (err != KM_ERROR_OK) { + return legacy_enum_conversion(err); + } + int len = i2d_KM_AUTH_LIST(kmAuthList.get(), nullptr); + if (len < 0) { + return legacy_enum_conversion(TranslateLastOpenSslError()); + } + + if (!derBlob.Reset(len)) { + return legacy_enum_conversion(KM_ERROR_MEMORY_ALLOCATION_FAILED); + } + + uint8_t* p = derBlob.writable_data(); + len = i2d_KM_AUTH_LIST(kmAuthList.get(), &p); + if (len < 0) { + return legacy_enum_conversion(TranslateLastOpenSslError()); + } + asn1ParamsVerified.insert(asn1ParamsVerified.begin(), p, p+len); + derBlob.release(); + } + return ErrorCode::OK; +} + +ErrorCode prepareCborArrayFromRawKey(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& blob, cppbor::Array& + array) { + ErrorCode errorCode = ErrorCode::OK; + AuthorizationSet paramSet; + keymaster_algorithm_t algorithm; + if(keyFormat == KeyFormat::PKCS8) { + + paramSet.Reinitialize(KmParamSet(keyParams)); + paramSet.GetTagValue(TAG_ALGORITHM, &algorithm); + + if(KM_ALGORITHM_RSA == algorithm) { + std::vector privExp; + std::vector modulus; + if(ErrorCode::OK != (errorCode = rsaRawKeyFromPKCS8(std::vector(blob), privExp, modulus))) { + return errorCode; + } + array.add(privExp); + array.add(modulus); + } else if(KM_ALGORITHM_EC == algorithm) { + std::vector privKey; + std::vector pubKey; + EcCurve curve; + if(ErrorCode::OK != (errorCode = ecRawKeyFromPKCS8(std::vector(blob), privKey, pubKey, curve))) { + return errorCode; + } + array.add(privKey); + array.add(pubKey); + } else { + return ErrorCode::UNSUPPORTED_ALGORITHM; + } + } else if(keyFormat == KeyFormat::RAW) { + array.add(std::vector(blob)); + } + return errorCode; +} + +ErrorCode parseWrappedKey(const hidl_vec& wrappedKeyData, std::vector& iv, std::vector& transitKey, +std::vector& secureKey, std::vector& tag, hidl_vec& authList, KeyFormat& +keyFormat, std::vector& wrappedKeyDescription) { + KeymasterBlob kmIv; + KeymasterKeyBlob kmTransitKey; + KeymasterKeyBlob kmSecureKey; + KeymasterBlob kmTag; + AuthorizationSet authSet; + keymaster_key_format_t kmKeyFormat; + KeymasterBlob kmWrappedKeyDescription; + + size_t keyDataLen = wrappedKeyData.size(); + uint8_t *keyData = dup_buffer(wrappedKeyData.data(), keyDataLen); + keymaster_key_blob_t keyMaterial = {keyData, keyDataLen}; + + keymaster_error_t error = parse_wrapped_key(KeymasterKeyBlob(keyMaterial), &kmIv, &kmTransitKey, + &kmSecureKey, &kmTag, &authSet, + &kmKeyFormat, &kmWrappedKeyDescription); + if (error != KM_ERROR_OK) return legacy_enum_conversion(error); + blob2Vec(kmIv.data, kmIv.data_length, iv); + blob2Vec(kmTransitKey.key_material, kmTransitKey.key_material_size, transitKey); + blob2Vec(kmSecureKey.key_material, kmSecureKey.key_material_size, secureKey); + blob2Vec(kmTag.data, kmTag.data_length, tag); + authList = kmParamSet2Hidl(authSet); + keyFormat = static_cast(kmKeyFormat); + blob2Vec(kmWrappedKeyDescription.data, kmWrappedKeyDescription.data_length, wrappedKeyDescription); + + return ErrorCode::OK; +} + +ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut) { + apduOut.push_back(static_cast(APDU_CLS)); //CLS + apduOut.push_back(static_cast(ins)); //INS + apduOut.push_back(static_cast(APDU_P1)); //P1 + apduOut.push_back(static_cast(APDU_P2)); //P2 + + if(UCHAR_MAX < inputData.size() && USHRT_MAX >= inputData.size()) { + //Extended length 3 bytes, starts with 0x00 + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(inputData.size() >> 8)); + apduOut.push_back(static_cast(inputData.size() & 0xFF)); + //Data + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + } else if(0 <= inputData.size() && UCHAR_MAX >= inputData.size()) { + //Short length + apduOut.push_back(static_cast(inputData.size())); + //Data + if(inputData.size() > 0) + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + + } else { + return (ErrorCode::INSUFFICIENT_BUFFER_SPACE); + } + + return (ErrorCode::OK);//success +} + +uint16_t getStatus(std::vector& inputData) { + //Last two bytes are the status SW0SW1 + return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); +} + +bool readDataFromFile(const char *filename, std::vector& data) { + FILE *fp; + bool ret = true; + fp = fopen(filename, "rb"); + if(fp == NULL) { + LOG(ERROR) << "Failed to open file: " << filename; + return false; + } + fseek(fp, 0L, SEEK_END); + long int filesize = ftell(fp); + rewind(fp); + std::unique_ptr buf(new uint8_t[filesize]); + if( 0 == fread(buf.get(), filesize, 1, fp)) { + LOG(ERROR) << "No Content in the file: " << filename; + ret = false; + } + if(true == ret) { + data.insert(data.begin(), buf.get(), buf.get() + filesize); + } + fclose(fp); + return ret; +} + +ErrorCode initiateProvision() { + /* This is just a reference implemenation */ + std::string brand("Google"); + std::string device("Pixel 3A"); + std::string product("Pixel"); + std::string serial("UGYJFDjFeRuBEH"); + std::string imei("987080543071019"); + std::string meid("27863510227963"); + std::string manufacturer("Foxconn"); + std::string model("HD1121"); + AuthorizationSet authSet(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) + .Authorization(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN) + .Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256) + .Authorization(TAG_KEY_SIZE, 2048) + .Authorization(TAG_PURPOSE, static_cast(0x7F)) /* The value 0x7F is not present in types.hal */ + .Authorization(TAG_ATTESTATION_ID_BRAND, brand.data(), brand.size()) + .Authorization(TAG_ATTESTATION_ID_DEVICE, device.data(), device.size()) + .Authorization(TAG_ATTESTATION_ID_PRODUCT, product.data(), product.size()) + .Authorization(TAG_ATTESTATION_ID_SERIAL, serial.data(), serial.size()) + .Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size()) + .Authorization(TAG_ATTESTATION_ID_MEID, meid.data(), meid.size()) + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, manufacturer.data(), manufacturer.size()) + .Authorization(TAG_ATTESTATION_ID_MODEL, model.data(), model.size())); + + hidl_vec keyParams = kmParamSet2Hidl(authSet); + std::vector data; + if(!readDataFromFile(ROOT_RSA_KEY, data)) { + LOG(ERROR) << " Failed to read the Root rsa key"; + return ErrorCode::UNKNOWN_ERROR; + } + return JavacardKeymaster4Device::provision(keyParams, KeyFormat::PKCS8, data); +} + +Return setBootParams() { + std::vector verifiedBootKey(32, 0); + std::vector verifiedBootKeyHash(32, 0); + + return JavacardKeymaster4Device::setBootParams(GetOsVersion(), GetOsPatchlevel(), verifiedBootKey, verifiedBootKeyHash, + KM_VERIFIED_BOOT_UNVERIFIED, 0/*deviceLocked*/); +} + +ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response) { + ErrorCode ret = ErrorCode::UNKNOWN_ERROR; + std::vector apdu; + + if(!android::base::GetBoolProperty(KM_JAVACARD_PROVISIONED_PROPERTY, false)) { + if(ErrorCode::OK != (ret = setBootParams())) { + LOG(ERROR) << "Failed to set boot params"; + return ret; + } + + if(ErrorCode::OK != (ret = initiateProvision())) { + LOG(ERROR) << "Failed to provision the device"; + return ret; + } + android::base::SetProperty(KM_JAVACARD_PROVISIONED_PROPERTY, "true"); + } + + ret = constructApduMessage(ins, inData, apdu); + if(ret != ErrorCode::OK) return ret; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + return (ErrorCode::OK);//success +} + +ErrorCode JavacardKeymaster4Device::provision(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& +keyData) { + cppbor::Array array; + cppbor::Array subArray; + std::unique_ptr item; + std::vector apdu; + hidl_vec keyBlob; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + Instruction ins = Instruction::INS_PROVISION_CMD; + std::vector response; + CborConverter cborConverter; + + if(ErrorCode::OK != (errorCode = prepareCborArrayFromRawKey(keyParams, keyFormat, keyData, subArray))) { + return errorCode; + } + /* construct cbor */ + cborConverter.addKeyparameters(array, keyParams); + array.add(static_cast(keyFormat)); + std::vector encodedArray = subArray.encode(); + cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); + array.add(bstr); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) + return errorCode; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + + if((response.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + } + return errorCode; +} + +ErrorCode JavacardKeymaster4Device::setBootParams(uint32_t osVersion, uint32_t osPatchLevel, const std::vector& verifiedBootKey, +std::vector& verifiedBootKeyHash, keymaster_verified_boot_t kmVerifiedBoot, bool deviceLocked) { + cppbor::Array array; + std::vector apdu; + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + array.add(osVersion). + add(osPatchLevel). + /* Verified Boot Key */ + add(verifiedBootKey). + /* Verified Boot Hash */ + add(verifiedBootKeyHash). + /* boot state */ + add(static_cast(kmVerifiedBoot)). + /* device locked */ + add(static_cast(deviceLocked)); + std::vector cborData = array.encode(); + + ErrorCode ret = constructApduMessage(ins, cborData, apdu); + if(ret != ErrorCode::OK) return ret; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + return ErrorCode::OK; + +} + +JavacardKeymaster4Device::JavacardKeymaster4Device(): softKm_(new ::keymaster::AndroidKeymaster( + []() -> auto { + auto context = new JavaCardSoftKeymasterContext(); + context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel()); + return context; + }(), + kOperationTableSize)), oprCtx_(new OperationContext()) { + +} + +JavacardKeymaster4Device::~JavacardKeymaster4Device() {} + +// Methods from IKeymasterDevice follow. +Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_cb) { + //_hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); + std::vector resp; + std::vector input; + std::unique_ptr item; + uint64_t securityLevel = static_cast(SecurityLevel::STRONGBOX); + hidl_string jcKeymasterName; + hidl_string jcKeymasterAuthor; + + ErrorCode ret = sendData(Instruction::INS_GET_HW_INFO_CMD, input, resp); + + if((ret == ErrorCode::OK) && (resp.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), + true); + if (item != nullptr) { + std::vector temp; + cborConverter_.getUint64(item, 0, securityLevel); //SecurityLevel + cborConverter_.getBinaryArray(item, 1, temp); + jcKeymasterName = std::string(temp.begin(), temp.end()); + temp.clear(); + cborConverter_.getBinaryArray(item, 2, temp); + jcKeymasterAuthor = std::string(temp.begin(), temp.end()); + } + } + _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); + return Void(); +} + +Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) { + std::vector cborData; + std::vector input; + std::unique_ptr item; + HmacSharingParameters hmacSharingParameters; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + errorCode = sendData(Instruction::INS_GET_HMAC_SHARING_PARAM_CMD, input, cborData); + + if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters); //HmacSharingParameters. + } + } + _hidl_cb(errorCode, hmacSharingParameters); + return Void(); +} + +Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + hidl_vec sharingCheck; + + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + std::vector tempVec; + cppbor::Array innerArray; + for(size_t i = 0; i < params.size(); ++i) { + innerArray.add(static_cast>(params[i].seed)); + for(size_t j = 0; i < params[j].nonce.size(); j++) { + tempVec.push_back(params[i].nonce[j]); + } + innerArray.add(tempVec); + tempVec.clear(); + } + array.add(std::move(innerArray)); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + std::vector bstr; + cborConverter_.getBinaryArray(item, 1, bstr); + sharingCheck.setToExternal(bstr.data(), bstr.size()); + } + } + _hidl_cb(errorCode, sharingCheck); + return Void(); +} + +Return JavacardKeymaster4Device::verifyAuthorization(uint64_t operationHandle, const hidl_vec& parametersToVerify, const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + VerificationToken verificationToken; + + /* Convert input data to cbor format */ + array.add(operationHandle); + cborConverter_.addKeyparameters(array, parametersToVerify); + cborConverter_.addHardwareAuthToken(array, authToken); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_VERIFY_AUTHORIZATION_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getVerificationToken(item, 1, verificationToken); + } + } + _hidl_cb(errorCode, verificationToken); + return Void(); +} + +Return JavacardKeymaster4Device::addRngEntropy(const hidl_vec& data) { + cppbor::Array array; + std::vector cborOutData; + std::unique_ptr item; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + /* Convert input data to cbor format */ + array.add(std::vector(data)); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_ADD_RNG_ENTROPY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +Return JavacardKeymaster4Device::generateKey(const hidl_vec& keyParams, generateKey_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + hidl_vec keyBlob; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + KeyCharacteristics keyCharacteristics; + + /* Convert to cbor format */ + cborConverter_.addKeyparameters(array, keyParams); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_GENERATE_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getBinaryArray(item, 1, keyBlob); + cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics); + } + } + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); +} + +Return JavacardKeymaster4Device::importKey(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& keyData, importKey_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + hidl_vec keyBlob; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + KeyCharacteristics keyCharacteristics; + cppbor::Array subArray; + + if(keyFormat != KeyFormat::PKCS8 && keyFormat != KeyFormat::RAW) { + _hidl_cb(ErrorCode::UNSUPPORTED_KEY_FORMAT, keyBlob, keyCharacteristics); + return Void(); + } + cborConverter_.addKeyparameters(array, keyParams); + array.add(static_cast(KeyFormat::RAW)); //javacard accepts only RAW. + if(ErrorCode::OK != (errorCode = prepareCborArrayFromRawKey(keyParams, keyFormat, keyData, subArray))) { + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); + } + std::vector encodedArray = subArray.encode(); + cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); + array.add(bstr); + + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_IMPORT_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getBinaryArray(item, 1, keyBlob); + cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics); + } + } + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); +} + +Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& wrappedKeyData, const hidl_vec& wrappingKeyBlob, const hidl_vec& maskingKey, const hidl_vec& unwrappingParams, uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + hidl_vec keyBlob; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + KeyCharacteristics keyCharacteristics; + std::vector iv; + std::vector transitKey; + std::vector secureKey; + std::vector tag; + hidl_vec authList; + KeyFormat keyFormat; + std::vector wrappedKeyDescription; + + if(ErrorCode::OK != (errorCode = parseWrappedKey(wrappedKeyData, iv, transitKey, secureKey, + tag, authList, keyFormat, wrappedKeyDescription))) { + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); + } + cborConverter_.addKeyparameters(array, authList); + array.add(static_cast(keyFormat)); + array.add(secureKey); + array.add(tag); + array.add(iv); + array.add(transitKey); + array.add(std::vector(wrappingKeyBlob)); + array.add(std::vector(maskingKey)); + cborConverter_.addKeyparameters(array, unwrappingParams); + array.add(std::vector(wrappedKeyDescription)); + array.add(passwordSid); + array.add(biometricSid); /* TODO if biometricSid optional if user not sent this don't encode this cbor format */ + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_IMPORT_WRAPPED_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getBinaryArray(item, 1, keyBlob); + cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics); + } + } + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + + return Void(); +} + +Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec& keyBlob, const hidl_vec& clientId, const hidl_vec& appData, getKeyCharacteristics_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + KeyCharacteristics keyCharacteristics; + + array.add(std::vector(keyBlob)); + array.add(std::vector(clientId)); + array.add(std::vector(appData)); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_GET_KEY_CHARACTERISTICS_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getKeyCharacteristics(item, 1, keyCharacteristics); + } + } + _hidl_cb(errorCode, keyCharacteristics); + return Void(); +} + +Return JavacardKeymaster4Device::exportKey(KeyFormat exportFormat, const hidl_vec& keyBlob, const hidl_vec& /*clientId*/, const hidl_vec& /*appData*/, exportKey_cb _hidl_cb) { + + ExportKeyRequest request; + request.key_format = legacy_enum_conversion(exportFormat); + request.SetKeyMaterial(keyBlob.data(), keyBlob.size()); + + ExportKeyResponse response; + softKm_->ExportKey(request, &response); + + hidl_vec resultKeyBlob; + if (response.error == KM_ERROR_OK) { + resultKeyBlob.setToExternal(response.key_data, response.key_data_length); + } + _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob); + return Void(); +} + +Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToAttest, const hidl_vec& attestParams, attestKey_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + hidl_vec keyBlob; + std::vector cborOutData; + hidl_vec> certChain; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + array.add(std::vector(keyToAttest)); + cborConverter_.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_ATTEST_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + std::vector> temp; + std::vector rootCert; + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getMultiBinaryArray(item, 1, temp); + } + if(readDataFromFile(ROOT_RSA_CERT, rootCert)) { + temp.push_back(std::move(rootCert)); + certChain.resize(temp.size()); + for(int i = 0; i < temp.size(); i++) { + certChain[i] = temp[i]; + } + } else { + LOG(ERROR) << "No root certificate found"; + } + } + _hidl_cb(errorCode, certChain); + return Void(); +} + +Return JavacardKeymaster4Device::upgradeKey(const hidl_vec& keyBlobToUpgrade, const hidl_vec& upgradeParams, upgradeKey_cb _hidl_cb) { + cppbor::Array array; + std::unique_ptr item; + hidl_vec upgradedKeyBlob; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + array.add(std::vector(keyBlobToUpgrade)); + cborConverter_.addKeyparameters(array, upgradeParams); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_UPGRADE_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getBinaryArray(item, 1, upgradedKeyBlob); + } + } + _hidl_cb(errorCode, upgradedKeyBlob); + return Void(); +} + +Return JavacardKeymaster4Device::deleteKey(const hidl_vec& keyBlob) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + array.add(std::vector(keyBlob)); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_DELETE_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +Return JavacardKeymaster4Device::deleteAllKeys() { + std::unique_ptr item; + std::vector cborOutData; + std::vector input; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + errorCode = sendData(Instruction::INS_DELETE_ALL_KEYS_CMD, input, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +Return JavacardKeymaster4Device::destroyAttestationIds() { + std::unique_ptr item; + std::vector cborOutData; + std::vector input; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + + errorCode = sendData(Instruction::INS_DESTROY_ATT_IDS_CMD, input, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec& keyBlob, const hidl_vec& inParams, const HardwareAuthToken& authToken, begin_cb _hidl_cb) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + hidl_vec outParams; + uint64_t operationHandle = 0; + hidl_vec resultParams; + + if(keyBlob.size() == 0) { + _hidl_cb(ErrorCode::INVALID_ARGUMENT, resultParams, operationHandle); + return Void(); + } + + if (KeyPurpose::ENCRYPT == purpose || KeyPurpose::VERIFY == purpose) { + BeginOperationRequest request; + request.purpose = legacy_enum_conversion(purpose); + request.SetKeyMaterial(keyBlob.data(), keyBlob.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + BeginOperationResponse response; + softKm_->BeginOperation(request, &response); + + if (response.error == KM_ERROR_OK) { + resultParams = kmParamSet2Hidl(response.output_params); + } + if (response.error != KM_ERROR_INCOMPATIBLE_ALGORITHM) { /*Incompatible algorithm could be handled by JavaCard*/ + _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle); + return Void(); + } + } + + cppbor::Array array; + std::vector cborOutData; + std::unique_ptr item; + std::unique_ptr blobItem = nullptr; + KeyCharacteristics keyCharacteristics; + + /* Convert input data to cbor format */ + array.add(static_cast(purpose)); + array.add(std::vector(keyBlob)); + cborConverter_.addKeyparameters(array, inParams); + cborConverter_.addHardwareAuthToken(array, authToken); + std::vector cborData = array.encode(); + + /* keyCharacteristics.hardwareEnforced is required to store algorithm, digest and padding values in operationInfo + * structure. To retrieve keyCharacteristics.hardwareEnforced, parse the keyBlob. + */ + /* TODO if keyBlob is corrupted it crashes in cbor */ + std::tie(blobItem, errorCode) = cborConverter_.decodeData(std::vector(keyBlob), false); + + if(blobItem == nullptr) { + _hidl_cb(errorCode, outParams, operationHandle); + return Void(); + } + errorCode = sendData(Instruction::INS_BEGIN_OPERATION_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getKeyParameters(item, 1, outParams); + cborConverter_.getUint64(item, 2, operationHandle); + /* Store the operationInfo */ + cborConverter_.getKeyCharacteristics(blobItem, 3, keyCharacteristics); + oprCtx_->setOperationInfo(operationHandle, purpose, keyCharacteristics.hardwareEnforced); + } + } + _hidl_cb(errorCode, outParams, operationHandle); + return Void(); +} + +Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + UpdateOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + UpdateOperationResponse response; + softKm_->UpdateOperation(request, &response); + + uint32_t inputConsumed = 0; + hidl_vec outParams; + hidl_vec output; + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + inputConsumed = response.input_consumed; + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } else if(response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + std::vector tempOut; + /* OperationContext calls this below sendDataCallback callback function. This callback + * may be called multiple times if the input data is larger than MAX_ALLOWED_INPUT_SIZE. + */ + auto sendDataCallback = [&](std::vector& data, bool) -> ErrorCode { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + std::vector asn1ParamsVerified; + + if(ErrorCode::OK != (errorCode = encodeParametersVerified(verificationToken, asn1ParamsVerified))) { + return errorCode; + } + + // Convert input data to cbor format + array.add(operationHandle); + cborConverter_.addKeyparameters(array, inParams); + array.add(data); + cborConverter_.addHardwareAuthToken(array, authToken); + cborConverter_.addVerificationToken(array, verificationToken, asn1ParamsVerified); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_UPDATE_OPERATION_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + /*Ignore inputConsumed from javacard SE since HAL consumes all the input */ + //cborConverter_.getUint64(item, 1, inputConsumed); + if(outParams.size() == 0) + cborConverter_.getKeyParameters(item, 2, outParams); + cborConverter_.getBinaryArray(item, 3, tempOut); + } + } + return errorCode; + }; + if(ErrorCode::OK == (errorCode = oprCtx_->update(operationHandle, std::vector(input), + sendDataCallback))) { + /* Consumed all the input */ + inputConsumed = input.size(); + output = tempOut; + } + } + if(ErrorCode::OK != errorCode) { + abort(operationHandle); + } + _hidl_cb(errorCode, inputConsumed, outParams, output); + return Void(); +} + +Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + FinishOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.signature.Reinitialize(signature.data(), signature.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + FinishOperationResponse response; + softKm_->FinishOperation(request, &response); + + hidl_vec outParams; + hidl_vec output; + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } else if (response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + std::vector tempOut; + /* OperationContext calls this below sendDataCallback callback function. This callback + * may be called multiple times if the input data is larger than MAX_ALLOWED_INPUT_SIZE. + * This callback function decides whether to call update/finish instruction based on the + * input received from the OperationContext through finish variable. + * if finish variable is false update instruction is called, if it is true finish instruction + * is called. + */ + auto sendDataCallback = [&](std::vector& data, bool finish) -> ErrorCode { + cppbor::Array array; + Instruction ins; + std::unique_ptr item; + std::vector cborOutData; + int keyParamPos, outputPos; + std::vector asn1ParamsVerified; + + if(ErrorCode::OK != (errorCode = encodeParametersVerified(verificationToken, asn1ParamsVerified))) { + return errorCode; + } + + // Convert input data to cbor format + array.add(operationHandle); + cborConverter_.addKeyparameters(array, inParams); + array.add(data); + if(finish) { + array.add(std::vector(signature)); + ins = Instruction::INS_FINISH_OPERATION_CMD; + keyParamPos = 1; + outputPos = 2; + } else { + ins = Instruction::INS_UPDATE_OPERATION_CMD; + keyParamPos = 2; + outputPos = 3; + } + cborConverter_.addHardwareAuthToken(array, authToken); + cborConverter_.addVerificationToken(array, verificationToken, asn1ParamsVerified); + std::vector cborData = array.encode(); + + errorCode = sendData(ins, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + if(outParams.size() == 0) + cborConverter_.getKeyParameters(item, keyParamPos, outParams); + cborConverter_.getBinaryArray(item, outputPos, tempOut); + } + } + return errorCode; + }; + if(ErrorCode::OK == (errorCode = oprCtx_->finish(operationHandle, std::vector(input), + sendDataCallback))) { + output = tempOut; + } + } + abort(operationHandle); + _hidl_cb(errorCode, outParams, output); + return Void(); +} + +Return JavacardKeymaster4Device::abort(uint64_t operationHandle) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + AbortOperationRequest request; + request.op_handle = operationHandle; + + AbortOperationResponse response; + softKm_->AbortOperation(request, &response); + + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + + /* Convert input data to cbor format */ + array.add(operationHandle); + std::vector cborData = array.encode(); + + errorCode = sendData(Instruction::INS_ABORT_OPERATION_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + } + /* Delete the entry on this operationHandle */ + oprCtx_->clearOperationData(operationHandle); + return errorCode; +} + +// Methods from ::android::hardware::keymaster::V4_1::IKeymasterDevice follow. +Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device::deviceLocked(bool passwordOnly, const VerificationToken& verificationToken) { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + ::android::hardware::keymaster::V4_1::ErrorCode errorCode = ::android::hardware::keymaster::V4_1::ErrorCode::UNKNOWN_ERROR; + std::vector asn1ParamsVerified; + ErrorCode ret = ErrorCode::UNKNOWN_ERROR; + + if(ErrorCode::OK != (ret = encodeParametersVerified(verificationToken, asn1ParamsVerified))) { + return errorCode; + } + + /* Convert input data to cbor format */ + array.add(passwordOnly); + cborConverter_.addVerificationToken(array, verificationToken, asn1ParamsVerified); + std::vector cborData = array.encode(); + + /* TODO DeviceLocked command handled inside HAL */ + ret = sendData(Instruction::INS_DEVICE_LOCKED_CMD, cborData, cborOutData); + + if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device::earlyBootEnded() { + std::unique_ptr item; + std::string message; + std::vector cborOutData; + std::vector cborInput; + ::android::hardware::keymaster::V4_1::ErrorCode errorCode = ::android::hardware::keymaster::V4_1::ErrorCode::UNKNOWN_ERROR; + + ErrorCode ret = sendData(Instruction::INS_EARLY_BOOT_ENDED_CMD, cborInput, cborOutData); + + if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + +} // javacard +} // namespace V4_1 +} // namespace keymaster diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp new file mode 100644 index 00000000..7e242162 --- /dev/null +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -0,0 +1,287 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include + +#define MAX_ALLOWED_INPUT_SIZE 512 +#define AES_BLOCK_SIZE 16 +#define DES_BLOCK_SIZE 8 +#define RSA_INPUT_MSG_LEN 245 /*(256-11)*/ +#define EC_INPUT_MSG_LEN 32 +#define MAX_RSA_BUFFER_SIZE 256 +#define MAX_EC_BUFFER_SIZE 32 + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +enum class Operation { + Update = 0, + Finish = 1 +}; + +inline ErrorCode hidlParamSet2OperatinInfo(const hidl_vec& params, OperationInfo& info) { + for(int i = 0; i < params.size(); i++) { + const KeyParameter ¶m = params[i]; + switch(param.tag) { + case Tag::ALGORITHM: + info.alg = static_cast(param.f.integer); + break; + case Tag::DIGEST: + info.digest = static_cast(param.f.integer); + break; + case Tag::PADDING: + info.pad = static_cast(param.f.integer); + break; + default: + continue; + } + } + return ErrorCode::OK; +} + +ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, const hidl_vec& params) { + ErrorCode errorCode = ErrorCode::OK; + OperationInfo info; + if(ErrorCode::OK != (errorCode = hidlParamSet2OperatinInfo(params, info))) { + return errorCode; + } + info.purpose = purpose; + return setOperationInfo(operationHandle, info); +} + +ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, OperationInfo& operInfo) { + OperationData data; + data.info = operInfo; + memset((void*)&(data.data), 0x00, sizeof(data.data)); + operationTable[operationHandle] = data; + return ErrorCode::OK; +} + +ErrorCode OperationContext::getOperationInfo(uint64_t operHandle, OperationInfo& operInfo) { + auto itr = operationTable.find(operHandle); + if(itr != operationTable.end()) { + operInfo = itr->second.info; + return ErrorCode::OK; + } + return ErrorCode::INVALID_OPERATION_HANDLE; +} + +ErrorCode OperationContext::clearOperationData(uint64_t operHandle) { + size_t size = operationTable.erase(operHandle); + if(!size) + return ErrorCode::INVALID_OPERATION_HANDLE; + else + return ErrorCode::OK; +} + +ErrorCode OperationContext::validateInputData(uint64_t operHandle, Operation opr, const std::vector& actualInput, std::vector& input) { + ErrorCode errorCode = ErrorCode::OK; + OperationData oprData; + + if(ErrorCode::OK != (errorCode = getOperationData(operHandle, oprData))) { + return errorCode; + } + + if(KeyPurpose::SIGN == oprData.info.purpose) { + if(Algorithm::RSA == oprData.info.alg && Digest::NONE == oprData.info.digest) { + if((oprData.data.buf_len+actualInput.size()) > RSA_INPUT_MSG_LEN) + return ErrorCode::INVALID_INPUT_LENGTH; + } else if(Algorithm::EC == oprData.info.alg && Digest::NONE == oprData.info.digest) { + /* Silently truncate the input */ + if(oprData.data.buf_len >= EC_INPUT_MSG_LEN) { + return ErrorCode::OK; + } else if(actualInput.size()+oprData.data.buf_len > EC_INPUT_MSG_LEN) { + for(int i=oprData.data.buf_len,j=0; i < EC_INPUT_MSG_LEN; ++i,++j) { + input.push_back(actualInput[j]); + } + return ErrorCode::OK; + } + } + } + + if(KeyPurpose::DECRYPT == oprData.info.purpose && Algorithm::RSA == oprData.info.alg) { + if((oprData.data.buf_len+actualInput.size()) > MAX_RSA_BUFFER_SIZE) { + return ErrorCode::INVALID_INPUT_LENGTH; + } + } + + if(opr == Operation::Finish) { + + if(oprData.info.pad == PaddingMode::NONE && oprData.info.alg == Algorithm::AES) { + if(((oprData.data.buf_len+actualInput.size()) % AES_BLOCK_SIZE) != 0) + return ErrorCode::INVALID_INPUT_LENGTH; + } + if(oprData.info.pad == PaddingMode::NONE && oprData.info.alg == Algorithm::TRIPLE_DES) { + if(((oprData.data.buf_len+actualInput.size()) % DES_BLOCK_SIZE) != 0) + return ErrorCode::INVALID_INPUT_LENGTH; + } + } + input = actualInput; + return errorCode; +} + +ErrorCode OperationContext::update(uint64_t operHandle, const std::vector& actualInput, sendDataToSE_cb cb) { + ErrorCode errorCode = ErrorCode::OK; + std::vector input; + + /* Validate the input data */ + if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Update, actualInput, input))) { + return errorCode; + } + + if (input.size() > MAX_ALLOWED_INPUT_SIZE) { + int noOfChunks = input.size()/MAX_ALLOWED_INPUT_SIZE; + int extraData = input.size()%MAX_ALLOWED_INPUT_SIZE; + for(int i =0 ; i < noOfChunks; i++) { + auto first = input.cbegin() + (i*MAX_ALLOWED_INPUT_SIZE); + auto end = first + MAX_ALLOWED_INPUT_SIZE; + std::vector newInput(first, end); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + if(extraData > 0) { + std::vector finalInput(input.cend()-extraData, input.cend()); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, finalInput.data(), finalInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + } else { + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, input.data(), input.size(), + Operation::Update, cb))) { + return errorCode; + } + } + return errorCode; +} + +ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector& actualInput, sendDataToSE_cb cb) { + ErrorCode errorCode = ErrorCode::OK; + std::vector input; + + /* Validate the input data */ + if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Update, actualInput, input))) { + return errorCode; + } + + if (input.size() > MAX_ALLOWED_INPUT_SIZE) { + int noOfChunks = input.size()/MAX_ALLOWED_INPUT_SIZE; + int extraData = input.size()%MAX_ALLOWED_INPUT_SIZE; + for(int i =0 ; i < noOfChunks; i++) { + auto first = input.cbegin() + (i*MAX_ALLOWED_INPUT_SIZE); + auto end = first + MAX_ALLOWED_INPUT_SIZE; + std::vector newInput(first, end); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + if(extraData > 0) { + std::vector finalInput(input.cend()-extraData, input.cend()); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, finalInput.data(), finalInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + } else { + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, input.data(), input.size(), + Operation::Update, cb))) { + return errorCode; + } + } + + /* Send if any buffered data is remaining or to call finish */ + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, nullptr, 0, + Operation::Finish, cb, true))) { + return errorCode; + } + return errorCode; +} + +ErrorCode OperationContext::internalUpdate(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& out) { + int dataToSELen=0; + /*Length of the data consumed from input */ + int inputConsumed=0; + bool dataSendToSE = true; + int blockSize = 0; + BufferedData& data = operationTable[operHandle].data; + int bufIndex = data.buf_len; + + if(Algorithm::AES == operationTable[operHandle].info.alg) { + blockSize = AES_BLOCK_SIZE; + } else if(Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { + blockSize = DES_BLOCK_SIZE; + } + + if(data.buf_len > 0) { + if(opr == Operation::Finish) { + //Copy the buffer to be send to SE. + for(int i = 0; i < data.buf_len; i++) + { + out.push_back(data.buf[i]); + } + dataToSELen = data.buf_len + input_len; + } else { + if (data.buf_len + input_len >= blockSize) { + dataToSELen = data.buf_len + input_len; + //Copy the buffer to be send to SE. + for(int i = 0; i < data.buf_len; i++) + { + out.push_back(data.buf[i]); + } + } else { + dataSendToSE = false; + } + } + } else { + dataToSELen = input_len; + } + + if(dataSendToSE) { + if(opr == Operation::Update) { + dataToSELen = (dataToSELen/blockSize) * blockSize; + } + inputConsumed = dataToSELen - data.buf_len; + + //Copy the buffer to be send to SE. + for(int i = 0; i < inputConsumed; i++) + { + out.push_back(input[i]); + } + + /* All the data is consumed so clear buffer */ + if(data.buf_len != 0) { + memset(data.buf, 0x00, sizeof(data.buf)); + bufIndex = data.buf_len = 0; + } + } + + //Store the remaining buffer for later use. + data.buf_len += (input_len - inputConsumed); + for(int i = 0; i < (input_len - inputConsumed); i++) + { + data.buf[bufIndex+i] = input[inputConsumed+i]; + } + return ErrorCode::OK; +} + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster diff --git a/HAL/keymaster/4.1/OmapiTransport.cpp b/HAL/keymaster/4.1/OmapiTransport.cpp new file mode 100644 index 00000000..5aaefc91 --- /dev/null +++ b/HAL/keymaster/4.1/OmapiTransport.cpp @@ -0,0 +1,49 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include "Transport.h" + +#define PORT 8080 +#define IPADDR "10.9.40.24" +#define UNUSED_V(a) a=a + +namespace se_transport { + +bool OmapiTransport::openConnection() { + return true; +} + +bool OmapiTransport::sendData(const uint8_t* inData, const size_t inLen, std::vector& output) { + std::vector test(inData, inData+inLen); + output = std::move(test); + return true; +} + +bool OmapiTransport::closeConnection() { + return true; +} + +bool OmapiTransport::isConnected() { + return true; +} + +} diff --git a/HAL/keymaster/4.1/SocketTransport.cpp b/HAL/keymaster/4.1/SocketTransport.cpp new file mode 100644 index 00000000..0dba18f9 --- /dev/null +++ b/HAL/keymaster/4.1/SocketTransport.cpp @@ -0,0 +1,96 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +#include +#include +#include +#include +#include "Transport.h" + +#define PORT 8080 +#define IPADDR "10.9.40.24" +#define MAX_RECV_BUFFER_SIZE 2048 + +namespace se_transport { + +bool SocketTransport::openConnection() { + struct sockaddr_in serv_addr; + if ((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + LOG(ERROR) << "Socket creation failed" << " Error: "<& output) { + uint8_t buffer[MAX_RECV_BUFFER_SIZE]; + int count = 1; + while(!socketStatus && count++ < 5 ) { + sleep(1); + LOG(ERROR) << "Trying to open socket connection... count: " << count; + openConnection(); + } + + if(count >= 5) { + LOG(ERROR) << "Failed to open socket connection"; + return false; + } + + if (0 > send(mSocket, inData, inLen , 0 )) { + LOG(ERROR) << "Failed to send data over socket."; + return false; + } + ssize_t valRead = read( mSocket , buffer, MAX_RECV_BUFFER_SIZE); + if(0 > valRead) { + LOG(ERROR) << "Failed to read data from socket."; + } + for(size_t i = 0; i < valRead; i++) { + output.push_back(buffer[i]); + } + return true; +} + +bool SocketTransport::closeConnection() { + close(mSocket); + socketStatus = false; + return true; +} + +bool SocketTransport::isConnected() { + //TODO + return socketStatus; +} + +} diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc new file mode 100644 index 00000000..1094c090 --- /dev/null +++ b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc @@ -0,0 +1,4 @@ +service vendor.keymaster-4-1 /vendor/bin/hw/android.hardware.keymaster@4.1-service.javacard + class early_hal + user nobody + group drmrpc diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml new file mode 100644 index 00000000..4fb320a6 --- /dev/null +++ b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml @@ -0,0 +1,11 @@ + + + android.hardware.keymaster + hwbinder + 4.1 + + IKeymasterDevice + default + + + diff --git a/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp b/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp new file mode 100644 index 00000000..1186b398 --- /dev/null +++ b/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::unique_ptr; +using ::keymaster::V4_1::javacard::KmParamSet; + +namespace keymaster { + +JavaCardSoftKeymasterContext::JavaCardSoftKeymasterContext(keymaster_security_level_t security_level) + : PureSoftKeymasterContext(security_level) {} + +JavaCardSoftKeymasterContext::~JavaCardSoftKeymasterContext() {} + +EVP_PKEY* RSA_fromMaterial(const uint8_t* modulus, size_t mod_size) { + BIGNUM *n = BN_bin2bn(modulus, mod_size, NULL); + BIGNUM *e = BN_new();//bignum_decode(exp, 5); + char exp[] = "65537"; + BN_dec2bn(&e, exp); + + if (!n || !e) + return NULL; + + if (e && n) { + EVP_PKEY* pRsaKey = EVP_PKEY_new(); + RSA* rsa = RSA_new(); + rsa->e = e; + rsa->n = n; + EVP_PKEY_assign_RSA(pRsaKey, rsa); + return pRsaKey; + } else { + if (n) BN_free(n); + if (e) BN_free(e); + return NULL; + } +} + +EC_GROUP* ChooseGroup(keymaster_ec_curve_t ec_curve) { + switch (ec_curve) { + case KM_EC_CURVE_P_224: + return EC_GROUP_new_by_curve_name(NID_secp224r1); + break; + case KM_EC_CURVE_P_256: + return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + break; + case KM_EC_CURVE_P_384: + return EC_GROUP_new_by_curve_name(NID_secp384r1); + break; + case KM_EC_CURVE_P_521: + return EC_GROUP_new_by_curve_name(NID_secp521r1); + break; + default: + return nullptr; + break; + } +} + +EVP_PKEY* EC_fromMaterial(const uint8_t* pub_key, size_t key_size, keymaster_ec_curve_t ec_curve) { + + EC_GROUP *ec_group = ChooseGroup(ec_curve); + EC_POINT *p = EC_POINT_new(ec_group); + EC_KEY *ec_key = EC_KEY_new(); + EVP_PKEY *pEcKey = EVP_PKEY_new(); + + if((EC_KEY_set_group(ec_key, ec_group) != 1) || (EC_POINT_oct2point(ec_group, p, pub_key, key_size, NULL) != 1) + || (EC_KEY_set_public_key(ec_key, p) != 1) || (EVP_PKEY_set1_EC_KEY(pEcKey, ec_key) != 1)) { + return NULL; + } + + return pEcKey; +} + +keymaster_error_t JavaCardSoftKeymasterContext::LoadKey(const keymaster_algorithm_t algorithm, KeymasterKeyBlob&& key_material, + AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, + UniquePtr* key) const { + auto factory = (AsymmetricKeyFactory*)GetKeyFactory(algorithm); + UniquePtr asym_key; + keymaster_error_t error = KM_ERROR_OK; + const uint8_t* tmp = key_material.key_material; + const size_t temp_size = key_material.key_material_size; + EVP_PKEY* pkey = NULL; + + if(algorithm == KM_ALGORITHM_RSA) { + pkey = RSA_fromMaterial(tmp, temp_size); + } else if(algorithm == KM_ALGORITHM_EC) { + keymaster_ec_curve_t ec_curve; + uint32_t keySize; + if (!hw_enforced.GetTagValue(TAG_EC_CURVE, &ec_curve) && + !sw_enforced.GetTagValue(TAG_EC_CURVE, &ec_curve)) { + if(!hw_enforced.GetTagValue(TAG_KEY_SIZE, &keySize) && + !sw_enforced.GetTagValue(TAG_KEY_SIZE, &keySize)) { + return KM_ERROR_INVALID_ARGUMENT; + } + error = EcKeySizeToCurve(keySize, &ec_curve); + if(error != KM_ERROR_OK) + return error; + } + pkey = EC_fromMaterial(tmp, temp_size, ec_curve); + } + if (!pkey) + return TranslateLastOpenSslError(); + UniquePtr pkey_deleter(pkey); + + error = factory->CreateEmptyKey(move(hw_enforced), move(sw_enforced), &asym_key); + if (error != KM_ERROR_OK) + return error; + + asym_key->key_material() = move(key_material); + if (!asym_key->EvpToInternal(pkey)) + error = TranslateLastOpenSslError(); + else + key->reset(asym_key.release()); + + return error; +} + +keymaster_error_t JavaCardSoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob, + const AuthorizationSet& /*additional_params*/, + UniquePtr* key) const { + + // The JavaCardSoftKeymasterContext handle a key blob generated by JavaCard keymaster for public key operations. + // + // 1. A JavaCard keymaster key blob is a CborEncoded data of Secret, Nonce, AuthTag, KeyCharectristics and Public key. + // Here in public key operation we need only KeyCharectristics and Public key. + // Once these values extracted Public key is created based on parameters and returned. + // + + AuthorizationSet hw_enforced; + AuthorizationSet sw_enforced; + KeymasterKeyBlob key_material; + keymaster_error_t error = KM_ERROR_OK; + + auto constructKey = [&, this] () mutable -> keymaster_error_t { + keymaster_algorithm_t algorithm; + if(error != KM_ERROR_OK) { + return error; + } + if (!hw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm) && + !sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) { + return KM_ERROR_INVALID_ARGUMENT; + } + + if (algorithm != KM_ALGORITHM_RSA && algorithm != KM_ALGORITHM_EC) { + return KM_ERROR_INCOMPATIBLE_ALGORITHM; + } + error = LoadKey(algorithm, move(key_material), move(hw_enforced), + move(sw_enforced), key); + return error; + }; + + CborConverter cc; + std::unique_ptr item; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + std::vector cborKey(blob.key_material_size); + + for(size_t i = 0; i < blob.key_material_size; i++) { + cborKey[i] = blob.key_material[i]; + } + std::tie(item, errorCode) = cc.decodeData(cborKey, false); + if (item != nullptr) { + std::vector temp(0); + if(cc.getBinaryArray(item, 4, temp)) { + key_material = {temp.data(), temp.size()}; + temp.clear(); + } + KeyCharacteristics keyCharacteristics; + cc.getKeyCharacteristics(item, 3, keyCharacteristics); + + sw_enforced.Reinitialize(KmParamSet(keyCharacteristics.softwareEnforced)); + hw_enforced.Reinitialize(KmParamSet(keyCharacteristics.hardwareEnforced)); + } else { + error = KM_ERROR_INVALID_KEY_BLOB; + } + return constructKey(); +} +} // namespace keymaster diff --git a/HAL/keymaster/4.1/service.cpp b/HAL/keymaster/4.1/service.cpp new file mode 100644 index 00000000..60123b5c --- /dev/null +++ b/HAL/keymaster/4.1/service.cpp @@ -0,0 +1,36 @@ +/* +** +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include + +int main() { + ::android::hardware::configureRpcThreadpool(1, true); + + auto keymaster = new ::android::hardware::keymaster::V4_1::JavacardKeymaster4Device(); + + auto status = keymaster->registerAsService(); + if (status != android::OK) { + LOG(FATAL) << "Could not register service for Keymaster 4.1 (" << status << ")"; + return -1; + } + + android::hardware::joinRpcThreadpool(); + return -1; // Should never get here. +} diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp new file mode 100644 index 00000000..bd253b43 --- /dev/null +++ b/HAL/keymaster/Android.bp @@ -0,0 +1,64 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library { + name: "libJavacardKeymaster41", + srcs: [ + "4.1/JavacardKeymaster4Device.cpp", + "4.1/CborConverter.cpp", + "4.1/java_card_soft_keymaster_context.cpp", + "4.1/JavacardOperationContext.cpp", + "4.1/CommonUtils.cpp", + ], + local_include_dirs: [ + "include", + ], + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "libsoftkeymasterdevice", + "libkeymaster_messages", + "libkeymaster_portable", + "libcppbor_external", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libjc_transport", + "libcrypto", + ], +} + +cc_library { + name: "libjc_transport", + host_supported: true, + vendor_available: true, + + srcs: [ + "4.1/SocketTransport.cpp", + "4.1/OmapiTransport.cpp" + ], + export_include_dirs: [ + "include" + ], + shared_libs: [ + "libbinder", + "libbase", + "liblog", + ], +} diff --git a/HAL/keymaster/include/CborConverter.h b/HAL/keymaster/include/CborConverter.h new file mode 100644 index 00000000..9ea2ef94 --- /dev/null +++ b/HAL/keymaster/include/CborConverter.h @@ -0,0 +1,231 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef __CBOR_CONVERTER_H_ +#define __CBOR_CONVERTER_H_ + +#include +#include +#include +#include +#include +#include + +using namespace cppbor; + +using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::HardwareAuthToken; +using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; +using ::android::hardware::keymaster::V4_0::HmacSharingParameters; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::VerificationToken; +using ::android::hardware::keymaster::V4_0::KeyCharacteristics; +using ::android::hardware::keymaster::V4_0::SecurityLevel; +using ::android::hardware::keymaster::V4_0::TagType; +using ::android::hardware::keymaster::V4_0::Tag; + +class CborConverter +{ + public: + CborConverter() = default; + ~CborConverter() = default; + + /** + * Parses the input data which is in CBOR format and returns a Tuple of Item pointer and the first element in the item pointer. + */ + template + std::tuple, T> decodeData(const std::vector& response, bool + hasErrorCode) { + const uint8_t* pos; + std::unique_ptr item(nullptr); + std::string message; + T errorCode = T::OK; + + std::tie(item, pos, message) = parse(response); + + if(item != nullptr && hasErrorCode) { + if(MajorType::ARRAY == getType(item)) { + if(!getErrorCode(item, 0, errorCode)) + item = nullptr; + } else if (MajorType::UINT == getType(item)) { + uint64_t err; + if(getUint64(item, err)) { + errorCode = static_cast(get2sCompliment(static_cast(err))); + } + item = nullptr; /*Already read the errorCode. So no need of sending item to client */ + } + } + return {std::move(item), errorCode}; + } + + /** + * Get the signed/unsigned integer value at a given position from the item pointer. + */ + template + bool getUint64(const std::unique_ptr& item, const uint32_t pos, T& value); + + /** + * Get the signed/unsigned integer value from the item pointer. + */ + template + bool getUint64(const std::unique_ptr& item, T& value); + + /** + * Get the HmacSharingParameters structure value at the given position from the item pointer. + */ + bool getHmacSharingParameters(const std::unique_ptr& item, const uint32_t pos, HmacSharingParameters& params); + + /** + * Get the Binary string at the given position from the item pointer. + */ + bool getBinaryArray(const std::unique_ptr& item, const uint32_t pos, std::vector& value); + + /** + * Get the Binary string at the given position from the item pointer. + */ + bool getBinaryArray(const std::unique_ptr& item, const uint32_t pos, + ::android::hardware::hidl_vec& value); + /** + * Get the HardwareAuthToken value at the given position from the item pointer. + */ + bool getHardwareAuthToken(const std::unique_ptr& item, const uint32_t pos, HardwareAuthToken& authType); + + /** + * Get the list of KeyParameters value at the given position from the item pointer. + */ + bool getKeyParameters(const std::unique_ptr& item, const uint32_t pos, android::hardware::hidl_vec& keyParams); + + /** + * Adds the the list of KeyParameters values to the Array item. + */ + bool addKeyparameters(Array& array, const android::hardware::hidl_vec& + keyParams); + + /** + * Add HardwareAuthToken value to the Array item. + */ + bool addHardwareAuthToken(Array& array, const HardwareAuthToken& + authToken); + + /** + * Get the VerificationToken value at the given position from the item pointer. + */ + bool getVerificationToken(const std::unique_ptr& item, const uint32_t pos, VerificationToken& + token); + + /** + * Get the KeyCharacteristics value at the given position from the item pointer. + */ + bool getKeyCharacteristics(const std::unique_ptr &item, const uint32_t pos, + KeyCharacteristics& keyCharacteristics); + + /** + * Get the list of binary arrays at the given position from the item pointer. + */ + bool getMultiBinaryArray(const std::unique_ptr& item, const uint32_t pos, + std::vector>& data); + + /** + * Add VerificationToken value to the Array item. + */ + bool addVerificationToken(Array& array, const VerificationToken& + verificationToken, std::vector& encodedParamsVerified); + + /** + * Get the ErrorCode value at the give position from the item pointer. + */ + template) || + (std::is_same_v)>> + inline bool getErrorCode(const std::unique_ptr& item, const uint32_t pos, T& errorCode) { + bool ret = false; + uint64_t errorVal; + if (!getUint64(item, pos, errorVal)) { + return ret; + } + errorCode = static_cast(get2sCompliment(static_cast(errorVal))); + + ret = true; + return ret; + } + + private: + /** + * Returns the negative value of the same number. + */ + inline int32_t get2sCompliment(uint32_t value) { return static_cast(~value+1); } + + /** + * Get the type of the Item pointer. + */ + inline MajorType getType(const std::unique_ptr &item) { return item.get()->type(); } + + /** + * Construct Keyparameter structure from the pair of key and value. If TagType is ENUM_REP the value contains + * binary string. If TagType is UINT_REP or ULONG_REP the value contains Array of unsigned integers. + */ + bool getKeyParameter(const std::pair&, + const std::unique_ptr&> pair, std::vector& keyParam); + + /** + * Get the sub item pointer from the root item pointer at the given position. + */ + inline void getItemAtPos(const std::unique_ptr& item, const uint32_t pos, std::unique_ptr& subItem) { + Array* arr = nullptr; + + if (MajorType::ARRAY != getType(item)) { + return; + } + arr = const_cast(item.get()->asArray()); + if (arr->size() < (pos + 1)) { + return; + } + subItem = std::move((*arr)[pos]); + } +}; + +template +bool CborConverter::getUint64(const std::unique_ptr& item, T& value) { + bool ret = false; + if ((item == nullptr) || + (std::is_unsigned::value && (MajorType::UINT != getType(item))) || + ((std::is_signed::value && (MajorType::NINT != getType(item))))) { + return ret; + } + + if (std::is_unsigned::value) { + const Uint* uintVal = item.get()->asUint(); + value = uintVal->value(); + } + else { + const Nint* nintVal = item.get()->asNint(); + value = nintVal->value(); + } + ret = true; + return ret; //success +} + +template +bool CborConverter::getUint64(const std::unique_ptr& item, const uint32_t pos, T& value) { + std::unique_ptr intItem(nullptr); + getItemAtPos(item, pos, intItem); + return getUint64(intItem, value); +} + + + +#endif diff --git a/HAL/keymaster/include/CommonUtils.h b/HAL/keymaster/include/CommonUtils.h new file mode 100644 index 00000000..a3feee14 --- /dev/null +++ b/HAL/keymaster/include/CommonUtils.h @@ -0,0 +1,98 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + + +#ifndef KEYMASTER_V4_1_JAVACARD_COMMONUTILS_H_ +#define KEYMASTER_V4_1_JAVACARD_COMMONUTILS_H_ + +#include +#include +#include + +namespace keymaster { +namespace V4_1 { +namespace javacard { +using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::Tag; +using ::android::hardware::keymaster::V4_0::KeyFormat; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::EcCurve; + +inline ErrorCode legacy_enum_conversion(const keymaster_error_t value) { + return static_cast(value); +} + +inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) { + return static_cast(value); +} + +inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) { + return static_cast(value); +} + +inline keymaster_tag_t legacy_enum_conversion(const Tag value) { + return keymaster_tag_t(value); +} + +inline Tag legacy_enum_conversion(const keymaster_tag_t value) { + return Tag(value); +} + +inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) { + return keymaster_tag_get_type(tag); +} + +inline hidl_vec kmBuffer2hidlVec(const ::keymaster::Buffer& buf) { + hidl_vec result; + result.setToExternal(const_cast(buf.peek_read()), buf.available_read()); + return result; +} + +inline void blob2Vec(const uint8_t *from, size_t size, std::vector& to) { + for(int i = 0; i < size; ++i) { + to.push_back(from[i]); + } +} + +keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec& keyParams); + +hidl_vec kmParamSet2Hidl(const keymaster_key_param_set_t& set); + +ErrorCode rsaRawKeyFromPKCS8(const std::vector& pkcs8Blob, std::vector& privateExp, std::vector& +pubModulus); + +ErrorCode ecRawKeyFromPKCS8(const std::vector& pkcs8Blob, std::vector& secret, std::vector& +publicKey, EcCurve& eccurve); + +class KmParamSet : public keymaster_key_param_set_t { + public: + explicit KmParamSet(const hidl_vec& keyParams) + : keymaster_key_param_set_t(hidlKeyParams2Km(keyParams)) {} + KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} { + other.length = 0; + other.params = nullptr; + } + KmParamSet(const KmParamSet&) = delete; + ~KmParamSet() { delete[] params; } +}; + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster +#endif //KEYMASTER_V4_1_JAVACARD_COMMONUTILS_H_ diff --git a/HAL/keymaster/include/JavacardKeymaster4Device.h b/HAL/keymaster/include/JavacardKeymaster4Device.h new file mode 100644 index 00000000..c7c06ed5 --- /dev/null +++ b/HAL/keymaster/include/JavacardKeymaster4Device.h @@ -0,0 +1,110 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef KEYMASTER_V4_1_JAVACARD_JAVACARDKEYMASTER4DEVICE_H_ +#define KEYMASTER_V4_1_JAVACARD_JAVACARDKEYMASTER4DEVICE_H_ + +#include +#include +#include +#include +#include "CborConverter.h" +#include "TransportFactory.h" +#include +#include +#include +#include + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; +using ::android::hardware::keymaster::V4_0::HardwareAuthToken; +using ::android::hardware::keymaster::V4_0::HmacSharingParameters; +using ::android::hardware::keymaster::V4_0::KeyCharacteristics; +using ::android::hardware::keymaster::V4_0::KeyFormat; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::OperationHandle; +using ::android::hardware::keymaster::V4_0::SecurityLevel; +using ::android::hardware::keymaster::V4_0::VerificationToken; +using ::android::hardware::keymaster::V4_1::IKeymasterDevice; +using ::android::hardware::keymaster::V4_0::Tag; + +using V41ErrorCode = ::android::hardware::keymaster::V4_1::ErrorCode; + +class JavacardKeymaster4Device : public IKeymasterDevice { + public: + + JavacardKeymaster4Device(); + virtual ~JavacardKeymaster4Device(); + + // Methods from ::android::hardware::keymaster::V4_0::IKeymasterDevice follow. + Return getHardwareInfo(getHardwareInfo_cb _hidl_cb) override; + Return getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override; + Return computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) override; + Return verifyAuthorization(uint64_t operationHandle, const hidl_vec& parametersToVerify, const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) override; + Return addRngEntropy(const hidl_vec& data) override; + Return generateKey(const hidl_vec& keyParams, generateKey_cb _hidl_cb) override; + Return importKey(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& keyData, importKey_cb _hidl_cb) override; + Return importWrappedKey(const hidl_vec& wrappedKeyData, const hidl_vec& wrappingKeyBlob, const hidl_vec& maskingKey, const hidl_vec& unwrappingParams, uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) override; + Return getKeyCharacteristics(const hidl_vec& keyBlob, const hidl_vec& clientId, const hidl_vec& appData, getKeyCharacteristics_cb _hidl_cb) override; + Return exportKey(KeyFormat keyFormat, const hidl_vec& keyBlob, const hidl_vec& clientId, const hidl_vec& appData, exportKey_cb _hidl_cb) override; + Return attestKey(const hidl_vec& keyToAttest, const hidl_vec& attestParams, attestKey_cb _hidl_cb) override; + Return upgradeKey(const hidl_vec& keyBlobToUpgrade, const hidl_vec& upgradeParams, upgradeKey_cb _hidl_cb) override; + Return deleteKey(const hidl_vec& keyBlob) override; + Return deleteAllKeys() override; + Return destroyAttestationIds() override; + Return begin(KeyPurpose purpose, const hidl_vec& keyBlob, const hidl_vec& inParams, const HardwareAuthToken& authToken, begin_cb _hidl_cb) override; + Return update(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) override; + Return finish(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) override; + Return abort(uint64_t operationHandle) override; + + // Methods from ::android::hardware::keymaster::V4_1::IKeymasterDevice follow. + Return deviceLocked(bool passwordOnly, const VerificationToken& verificationToken) override; + Return earlyBootEnded() override; + + //Set Boot Params + /* This method should be called at the time when HAL is initialized for the first time */ + static ErrorCode setBootParams(uint32_t osVersion, uint32_t osPatchLevel, const std::vector& verifiedBootKey, +std::vector& verifiedBootKeyHash, keymaster_verified_boot_t kmVerifiedBoot, bool deviceLocked); + + //Provision Method + /* Reference for vendor to provision the javacard. This should happen only once at the time of production.*/ + static ErrorCode provision(const hidl_vec& keyParams, KeyFormat keyformat, const hidl_vec& +keyData); + +protected: + CborConverter cborConverter_; + +private: + std::unique_ptr<::keymaster::AndroidKeymaster> softKm_; + std::unique_ptr oprCtx_; +}; + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster + +#endif // KEYMASTER_V4_1_JAVACARD_JAVACARDKEYMASTER4DEVICE_H_ diff --git a/HAL/keymaster/include/JavacardOperationContext.h b/HAL/keymaster/include/JavacardOperationContext.h new file mode 100644 index 00000000..7a6fb706 --- /dev/null +++ b/HAL/keymaster/include/JavacardOperationContext.h @@ -0,0 +1,154 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ +#define KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ + +#include +#include + +#define MAX_BUF_SIZE 256 + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::Algorithm; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::Digest; +using ::android::hardware::keymaster::V4_0::PaddingMode; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::Tag; + +using sendDataToSE_cb = std::function& data, bool finish)>; + +enum class Operation; + +struct BufferedData { + uint8_t buf[MAX_BUF_SIZE]; + size_t buf_len; +}; + +struct OperationInfo { + Algorithm alg; + KeyPurpose purpose; + Digest digest; + PaddingMode pad; +}; + +struct OperationData { + OperationInfo info; + BufferedData data; +}; + +class OperationContext { + +public: + OperationContext(){} + ~OperationContext() {} + ErrorCode setOperationInfo(uint64_t operationHandle, OperationInfo& oeprInfo); + ErrorCode setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, const hidl_vec& params); + ErrorCode getOperationInfo(uint64_t operHandle, OperationInfo& operInfo); + ErrorCode clearOperationData(uint64_t operationHandle); + ErrorCode update(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); + ErrorCode finish(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); + +private: + std::map operationTable; + + inline ErrorCode getOperationData(uint64_t operHandle, OperationData& oprData) { + auto itr = operationTable.find(operHandle); + if(itr != operationTable.end()) { + oprData = itr->second; + return ErrorCode::OK; + } + return ErrorCode::INVALID_OPERATION_HANDLE; + } + + ErrorCode validateInputData(uint64_t operHandle, Operation opr, const std::vector& actualInput, + std::vector& input); + ErrorCode internalUpdate(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& + out); + ErrorCode handleInternalUpdate(uint64_t operHandle, uint8_t* data, size_t len, Operation opr, + sendDataToSE_cb cb, bool finish=false) { + ErrorCode errorCode = ErrorCode::OK; + std::vector out; + + if(Algorithm::AES == operationTable[operHandle].info.alg || + Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { + if(ErrorCode::OK != (errorCode = internalUpdate(operHandle, data, len, + opr, out))) { + return errorCode; + } + if(finish || out.size() > 0) { + + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } + } else { + /* Asymmetric */ + if(operationTable[operHandle].info.purpose == KeyPurpose::DECRYPT || + operationTable[operHandle].info.digest == Digest::NONE) { + /* In case of Decrypt, sign with no digest cases buffer the data in + * update call and send data to SE in finish call. + */ + if(finish) { + for(size_t i = 0; i < operationTable[operHandle].data.buf_len; ++i) { + out.push_back(operationTable[operHandle].data.buf[i]); + } + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } else { + //Input message length should not be more than the MAX_BUF_SIZE. + if(operationTable[operHandle].data.buf_len <= MAX_BUF_SIZE) { + size_t bufIndex = operationTable[operHandle].data.buf_len; + size_t pos = 0; + for(; (pos < len) && (pos < (MAX_BUF_SIZE-bufIndex)); pos++) + { + operationTable[operHandle].data.buf[bufIndex+pos] = data[pos]; + } + operationTable[operHandle].data.buf_len += pos; + } + } + } else { + for(size_t j=0; j < len; ++j) + { + out.push_back(data[j]); + } + /* if len=0, then no need to call the callback, since there is no information to be send to javacard, + * but if finish flag is true irrespective of length the callback should be called. + */ + if(len != 0 || finish) { + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } + } + } + return errorCode; + } +}; + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster + +#endif // KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ diff --git a/HAL/keymaster/include/Transport.h b/HAL/keymaster/include/Transport.h new file mode 100644 index 00000000..4c230b0a --- /dev/null +++ b/HAL/keymaster/include/Transport.h @@ -0,0 +1,111 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +#ifndef __SE_TRANSPORT__ +#define __SE_TRANSPORT__ + +namespace se_transport { + +/** + * ITransport is an abstract interface with a set of virtual methods that allow communication between the keymaster + * HAL and the secure element. + */ +class ITransport { + public: + virtual ~ITransport(){} + + /** + * Opens connection. + */ + virtual bool openConnection() = 0; + /** + * Send data over communication channel and receives data back from the remote end. + */ + virtual bool sendData(const uint8_t* inData, const size_t inLen, std::vector& output) = 0; + /** + * Closes the connection. + */ + virtual bool closeConnection() = 0; + /** + * Returns the state of the connection status. Returns true if the connection is active, false if connection is + * broken. + */ + virtual bool isConnected() = 0; + +}; + +/** + * OmapiTransport is derived from ITransport. This class gets the OMAPI service binder instance and uses IPC to + * communicate with OMAPI service. OMAPI inturn communicates with hardware via ISecureElement. + */ +class OmapiTransport : public ITransport { + +public: + + /** + * Gets the binder instance of ISEService, gets the reader corresponding to secure element, establishes a session + * and opens a basic channel. + */ + bool openConnection() override; + /** + * Transmists the data over the opened basic channel and receives the data back. + */ + bool sendData(const uint8_t* inData, const size_t inLen, std::vector& output) override; + /** + * Closes the connection. + */ + bool closeConnection() override; + /** + * Returns the state of the connection status. Returns true if the connection is active, false if connection is + * broken. + */ + bool isConnected() override; + +}; + +class SocketTransport : public ITransport { + +public: + SocketTransport() : socketStatus(false) { + } + /** + * Creates a socket instance and connects to the provided server IP and port. + */ + bool openConnection() override; + /** + * Sends data over socket and receives data back. + */ + bool sendData(const uint8_t* inData, const size_t inLen, std::vector& output) override; + /** + * Closes the connection. + */ + bool closeConnection() override; + /** + * Returns the state of the connection status. Returns true if the connection is active, false if connection is + * broken. + */ + bool isConnected() override; +private: + /** + * Socket instance. + */ + int mSocket; + bool socketStatus; + +}; + +} +#endif /* __SE_TRANSPORT__ */ diff --git a/HAL/keymaster/include/TransportFactory.h b/HAL/keymaster/include/TransportFactory.h new file mode 100644 index 00000000..b09e3ba9 --- /dev/null +++ b/HAL/keymaster/include/TransportFactory.h @@ -0,0 +1,76 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ +#ifndef __SE_TRANSPORT_FACTORY__ +#define __SE_TRANSPORT_FACTORY__ + +#include "Transport.h" + +namespace se_transport { + +/** + * TransportFactory class decides which transport mechanism to be used to send data to secure element. In case of + * emulator the communication channel is socket and in case of device the communication channel is via OMAPI. + */ +class TransportFactory { + public: + TransportFactory(bool isEmulator) { + if (!isEmulator) + mTransport = std::unique_ptr(new OmapiTransport()); + else + mTransport = std::unique_ptr(new SocketTransport()); + } + + ~TransportFactory() {} + + /** + * Establishes a communication channel with the secure element. + */ + inline bool openConnection() { + return mTransport->openConnection(); + } + + /** + * Sends the data to the secure element and also receives back the data. + * This is a blocking call. + */ + inline bool sendData(const uint8_t* inData, const size_t inLen, std::vector& output) { + return mTransport->sendData(inData, inLen, output); + } + + /** + * Close the connection. + */ + inline bool closeConnection() { + return mTransport->closeConnection(); + } + + /** + * Returns the connection status of the communication channel. + */ + inline bool isConnected() { + return mTransport->isConnected(); + } + + private: + /** + * Holds the instance of either OmapiTransport class or SocketTransport class. + */ + std::unique_ptr mTransport; + +}; +} +#endif /* __SE_TRANSPORT_FACTORY__ */ diff --git a/HAL/keymaster/include/java_card_soft_keymaster_context.h b/HAL/keymaster/include/java_card_soft_keymaster_context.h new file mode 100644 index 00000000..0fa2d711 --- /dev/null +++ b/HAL/keymaster/include/java_card_soft_keymaster_context.h @@ -0,0 +1,51 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_JAVA_CARD_SOFT_KEYMASTER_CONTEXT_H_ +#define SYSTEM_KEYMASTER_JAVA_CARD_SOFT_KEYMASTER_CONTEXT_H_ + +#include + +namespace keymaster { + +class SoftKeymasterKeyRegistrations; +class Keymaster0Engine; +class Keymaster1Engine; +class Key; + +/** + * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster. + */ +class JavaCardSoftKeymasterContext : public keymaster::PureSoftKeymasterContext { + keymaster_error_t LoadKey(const keymaster_algorithm_t algorithm, KeymasterKeyBlob&& key_material, + AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, + UniquePtr* key) const; + public: + // Security level must only be used for testing. + explicit JavaCardSoftKeymasterContext( + keymaster_security_level_t security_level = KM_SECURITY_LEVEL_SOFTWARE); + ~JavaCardSoftKeymasterContext() override; + + keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob, + const AuthorizationSet& additional_params, + UniquePtr* key) const override; + +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_PURE_SOFT_KEYMASTER_CONTEXT_H_