Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 4 additions & 8 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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) {
Expand Down
22 changes: 20 additions & 2 deletions Applet/src/com/android/javacard/keymaster/KMOperationState.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 5 additions & 1 deletion Applet/src/com/android/javacard/keymaster/KMType.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions HAL/JavacardKeyMintDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>(item, 2, opHandle) ||
!cbor_.getUint64<uint8_t>(item, 3, bufMode)) {
!cbor_.getUint64<uint8_t>(item, 3, bufMode) ||
!cbor_.getUint64<uint16_t>(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<JavacardKeyMintOperation>(
static_cast<keymaster_operation_handle_t>(opHandle), static_cast<BufferingMode>(bufMode),
card_);
macLength, card_);
return ScopedAStatus::ok();
}

Expand Down
46 changes: 39 additions & 7 deletions HAL/JavacardKeyMintOperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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_) {
Expand All @@ -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;
Expand Down
19 changes: 14 additions & 5 deletions HAL/JavacardKeyMintOperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
#include <hardware/keymaster_defs.h>
#include <vector>

#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
Expand All @@ -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.
Expand All @@ -61,9 +67,10 @@ class JavacardKeyMintOperation : public BnKeyMintOperation {
public:
explicit JavacardKeyMintOperation(keymaster_operation_handle_t opHandle,
BufferingMode bufferingMode,
uint16_t macLength,
shared_ptr<JavacardSecureElement> card)
: buffer_(vector<uint8_t>()), bufferingMode_(bufferingMode), card_(card),
opHandle_(opHandle) {}
: buffer_(vector<uint8_t>()), bufferingMode_(bufferingMode), macLength_(macLength),
card_(card), opHandle_(opHandle) {}
virtual ~JavacardKeyMintOperation();

ScopedAStatus updateAad(const vector<uint8_t>& input,
Expand Down Expand Up @@ -109,10 +116,12 @@ class JavacardKeyMintOperation : public BnKeyMintOperation {
std::tuple<std::unique_ptr<Item>, 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<uint8_t> buffer_;
BufferingMode bufferingMode_;
uint16_t macLength_;
const shared_ptr<JavacardSecureElement> card_;
keymaster_operation_handle_t opHandle_;
CborConverter cbor_;
Expand Down
40 changes: 27 additions & 13 deletions HAL/keymint_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
Expand All @@ -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(&regex, kPatchlevelRegex, REG_EXTENDED) != 0) {
return 0;
Expand All @@ -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