diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 95540bdb..aaf93834 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -57,7 +57,7 @@ public class KMAndroidSEProvider implements KMSEProvider { public static final short AES_GCM_NONCE_LENGTH = 12; public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; - public static final short TMP_ARRAY_SIZE = 256; + public static final short TMP_ARRAY_SIZE = 300; private static final short RSA_KEY_SIZE = 256; public static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 512;//First 2 bytes for length. diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 30b229d2..b8483275 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -2101,16 +2101,10 @@ private void processUpdateOperationCmd(APDU apdu) { short len = KMByteBlob.cast(data[INPUT_DATA]).length(); short additionalExpOutLen = 0; if (op.getAlgorithm() == KMType.AES) { - if (op.getBlockMode() == KMType.GCM) { + if (op.getBlockMode() == KMType.GCM || op.getBlockMode() == KMType.CTR) { if(op.isAesGcmUpdateAllowed()){ op.setAesGcmUpdateComplete(); } - // if input data present then it should be block aligned. - if (len > 0) { - if (len % AES_BLOCK_SIZE != 0) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - } additionalExpOutLen = 16; } else { // input data must be block aligned. @@ -2332,11 +2326,12 @@ private void processBeginOperationCmd(APDU apdu) { } short params = KMKeyParameters.instance(iv); - short resp = KMArray.instance((short) 4); + short resp = KMArray.instance((short) 5); KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(resp).add((short) 1, params); KMArray.cast(resp).add((short) 2, data[OP_HANDLE]); KMArray.cast(resp).add((short) 3, KMInteger.uint_8(op.getBufferingMode())); + KMArray.cast(resp).add((short) 4, KMInteger.uint_16((short) (op.getMacLength() / 8))); sendOutgoing(apdu, resp); } @@ -4042,6 +4037,7 @@ private void add(byte[] buf, short op1, short op2, short result) { public void powerReset() { //TODO handle power reset signal. releaseAllOperations(); + resetWrappingKey(); } public static void generateRkpKey(byte[] scratchPad, short keyParams) { diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 8d928427..df2bcbb3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -337,15 +337,33 @@ public byte getBufferingMode(){ short alg = getAlgorithm(); short purpose = getPurpose(); short digest = getDigest(); + short padding = getPadding(); + short blockMode = getBlockMode(); if(alg == KMType.RSA && digest == KMType.DIGEST_NONE && purpose == KMType.SIGN){ return KMType.BUF_RSA_NO_DIGEST; } + if(alg == KMType.EC && digest == KMType.DIGEST_NONE && purpose == KMType.SIGN){ return KMType.BUF_EC_NO_DIGEST; } - if(alg == KMType.AES || alg == KMType.DES){ - return KMType.BUF_BLOCK_ALIGN; + + switch(alg) { + case KMType.AES: + if (purpose == KMType.DECRYPT && padding == KMType.PKCS7) { + return KMType.BUF_AES_PKCS7_DECRYPT_BLOCK_ALIGN; + } else if (purpose == KMType.DECRYPT && blockMode == KMType.GCM) { + return KMType.BUF_AES_GCM_DECRYPT_BLOCK_ALIGN; + } else if (blockMode == KMType.CBC || blockMode == KMType.ECB) { + return KMType.BUF_AES_BLOCK_ALIGN; + } + break; + case KMType.DES: + if (purpose == KMType.DECRYPT && padding == KMType.PKCS7) { + return KMType.BUF_DES_PKCS7_DECRYPT_BLOCK_ALIGN; + } else { + return KMType.BUF_DES_BLOCK_ALIGN; + } } return KMType.BUF_NONE; } diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index a1352c78..499c7636 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -349,7 +349,11 @@ public abstract class KMType { public static final byte BUF_NONE = 0; public static final byte BUF_RSA_NO_DIGEST = 1; public static final byte BUF_EC_NO_DIGEST = 2; - public static final byte BUF_BLOCK_ALIGN = 3; + public static final byte BUF_AES_BLOCK_ALIGN = 3; + public static final byte BUF_AES_PKCS7_DECRYPT_BLOCK_ALIGN = 4; + public static final byte BUF_DES_BLOCK_ALIGN = 5; + public static final byte BUF_DES_PKCS7_DECRYPT_BLOCK_ALIGN = 6; + public static final byte BUF_AES_GCM_DECRYPT_BLOCK_ALIGN = 7; protected static KMRepository repository; protected static byte[] heap; diff --git a/HAL/JavacardKeyMintDevice.cpp b/HAL/JavacardKeyMintDevice.cpp index 43606534..402504b3 100644 --- a/HAL/JavacardKeyMintDevice.cpp +++ b/HAL/JavacardKeyMintDevice.cpp @@ -296,16 +296,18 @@ ScopedAStatus JavacardKeyMintDevice::begin(KeyPurpose purpose, const std::vector // return the result uint64_t opHandle; uint8_t bufMode; + uint16_t macLength; if (!cbor_.getKeyParameters(item, 1, result->params) || !cbor_.getUint64(item, 2, opHandle) || - !cbor_.getUint64(item, 3, bufMode)) { + !cbor_.getUint64(item, 3, bufMode) || + !cbor_.getUint64(item, 4, macLength)) { LOG(ERROR) << "Error in decoding the response in begin."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } result->challenge = opHandle; result->operation = ndk::SharedRefBase::make( static_cast(opHandle), static_cast(bufMode), - card_); + macLength, card_); return ScopedAStatus::ok(); } diff --git a/HAL/JavacardKeyMintOperation.cpp b/HAL/JavacardKeyMintOperation.cpp index 20e02297..d4952aa0 100644 --- a/HAL/JavacardKeyMintOperation.cpp +++ b/HAL/JavacardKeyMintOperation.cpp @@ -104,12 +104,9 @@ ScopedAStatus JavacardKeyMintOperation::abort() { return km_utils::kmError2ScopedAStatus(err); } -void JavacardKeyMintOperation::blockAlign(DataView& view, short blockSize) { +void JavacardKeyMintOperation::blockAlign(DataView& view, uint16_t blockSize) { appendBufferedData(view); - short offset = ((view.length / blockSize) - 1) * blockSize; - if (offset <= 0) { - offset = 0; - } + uint16_t offset = getDataViewOffset(view, blockSize); if (view.buffer.empty() && view.data.empty()) { offset = 0; } else if (view.buffer.empty()) { @@ -129,6 +126,33 @@ void JavacardKeyMintOperation::blockAlign(DataView& view, short blockSize) { view.length = view.length - buffer_.size(); } +uint16_t JavacardKeyMintOperation::getDataViewOffset(DataView& view, uint16_t blockSize) { + uint16_t offset = 0; + uint16_t remaining = 0; + switch(bufferingMode_) { + case BufferingMode::BUF_AES_BLOCK_ALIGNED: + case BufferingMode::BUF_DES_BLOCK_ALIGNED: + offset = ((view.length / blockSize)) * blockSize; + break; + case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED: + case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED: + offset = ((view.length / blockSize)) * blockSize; + remaining = (view.length % blockSize); + if (offset >= blockSize && remaining == 0) { + offset -= blockSize; + } + break; + case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED: + if (view.length > macLength_) { + offset = (view.length - macLength_); + } + break; + default: + break; + } + return offset; +} + keymaster_error_t JavacardKeyMintOperation::bufferData(DataView& view) { if (view.data.empty()) return KM_ERROR_OK; // nothing to buffer switch (bufferingMode_) { @@ -152,8 +176,16 @@ keymaster_error_t JavacardKeyMintOperation::bufferData(DataView& view) { view.start = 0; view.length = 0; break; - case BufferingMode::BLOCK_ALIGNED: - blockAlign(view, BLOCK_SIZE); + case BufferingMode::BUF_AES_BLOCK_ALIGNED: + case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED: + blockAlign(view, AES_BLOCK_SIZE); + break; + case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED: + blockAlign(view, macLength_); + break; + case BufferingMode::BUF_DES_BLOCK_ALIGNED: + case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED: + blockAlign(view, DES_BLOCK_SIZE); break; case BufferingMode::NONE: break; diff --git a/HAL/JavacardKeyMintOperation.h b/HAL/JavacardKeyMintOperation.h index 0e04b778..4f5fc046 100644 --- a/HAL/JavacardKeyMintOperation.h +++ b/HAL/JavacardKeyMintOperation.h @@ -24,7 +24,8 @@ #include #include -#define BLOCK_SIZE 16 +#define AES_BLOCK_SIZE 16 +#define DES_BLOCK_SIZE 8 #define RSA_BUFFER_SIZE 256 #define EC_BUFFER_SIZE 32 #define MAX_CHUNK_SIZE 256 @@ -45,7 +46,12 @@ enum class BufferingMode : int32_t { // will further check according to exact key size and crypto provider. EC_NO_DIGEST = 2, // Buffer upto 65 bytes and then truncate. Javacard will further truncate // upto exact keysize. - BLOCK_ALIGNED = 3, // Buffer the atlest 16 bytes and reminder to make input data block aligned. + BUF_AES_BLOCK_ALIGNED = 3, // Buffer 15 bytes and reminder to make input data block aligned. + BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED = 4, // Buffer 16 bytes. + BUF_DES_BLOCK_ALIGNED = 5, // Buffer 7 bytes and reminder to make input data block aligned. + BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED = 6, // Buffer 8 bytes. + BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED = 7, // Buffer 16 bytes. + }; // The is the view in the input data being processed by update/finish funcion. @@ -61,9 +67,10 @@ class JavacardKeyMintOperation : public BnKeyMintOperation { public: explicit JavacardKeyMintOperation(keymaster_operation_handle_t opHandle, BufferingMode bufferingMode, + uint16_t macLength, shared_ptr card) - : buffer_(vector()), bufferingMode_(bufferingMode), card_(card), - opHandle_(opHandle) {} + : buffer_(vector()), bufferingMode_(bufferingMode), macLength_(macLength), + card_(card), opHandle_(opHandle) {} virtual ~JavacardKeyMintOperation(); ScopedAStatus updateAad(const vector& input, @@ -109,10 +116,12 @@ class JavacardKeyMintOperation : public BnKeyMintOperation { std::tuple, keymaster_error_t> sendRequest(Instruction ins, Array& request); keymaster_error_t bufferData(DataView& data); - void blockAlign(DataView& data, short blockSize); + void blockAlign(DataView& data, uint16_t blockSize); + uint16_t getDataViewOffset(DataView& view, uint16_t blockSize); vector buffer_; BufferingMode bufferingMode_; + uint16_t macLength_; const shared_ptr card_; keymaster_operation_handle_t opHandle_; CborConverter cbor_; diff --git a/HAL/keymint_utils.cpp b/HAL/keymint_utils.cpp index c19c5fd7..a98de129 100644 --- a/HAL/keymint_utils.cpp +++ b/HAL/keymint_utils.cpp @@ -31,10 +31,11 @@ constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch"; -constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; +constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$"; constexpr size_t kYearMatch = 1; constexpr size_t kMonthMatch = 2; -constexpr size_t kPatchlevelMatchCount = kMonthMatch + 1; +constexpr size_t kDayMatch = 3; +constexpr size_t kPatchlevelMatchCount = kDayMatch + 1; uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { if (match.rm_so == -1) return 0; @@ -46,14 +47,12 @@ uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { std::string wait_and_get_property(const char* prop) { std::string prop_value; - // while (!::android::base::WaitForPropertyCreation(prop)) + while (!::android::base::WaitForPropertyCreation(prop)) ; prop_value = ::android::base::GetProperty(prop, "" /* default */); return prop_value; } -} // anonymous namespace - uint32_t getOsVersion(const char* version_str) { regex_t regex; if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { @@ -75,12 +74,9 @@ uint32_t getOsVersion(const char* version_str) { return (major * 100 + minor) * 100 + subminor; } -uint32_t getOsVersion() { - std::string version = wait_and_get_property(kPlatformVersionProp); - return getOsVersion(version.c_str()); -} +enum class PatchlevelOutput { kYearMonthDay, kYearMonth }; -uint32_t getPatchlevel(const char* patchlevel_str) { +uint32_t getPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) { regex_t regex; if (regcomp(®ex, kPatchlevelRegex, REG_EXTENDED) != 0) { return 0; @@ -99,17 +95,35 @@ uint32_t getPatchlevel(const char* patchlevel_str) { if (month < 1 || month > 12) { return 0; } - return year * 100 + month; + + switch (detail) { + case PatchlevelOutput::kYearMonthDay: { + uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]); + if (day < 1 || day > 31) { + return 0; + } + return year * 10000 + month * 100 + day; + } + case PatchlevelOutput::kYearMonth: + return year * 100 + month; + } +} + +} // anonymous namespace + +uint32_t getOsVersion() { + std::string version = wait_and_get_property(kPlatformVersionProp); + return getOsVersion(version.c_str()); } uint32_t getOsPatchlevel() { std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp); - return getPatchlevel(patchlevel.c_str()); + return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonth); } uint32_t getVendorPatchlevel() { std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp); - return getPatchlevel(patchlevel.c_str()); + return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay); } } // namespace keymint::javacard