Merge "keystore: Add flag for blobs to be unencrypted" into jb-mr2-dev
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index e899c12..46f7244 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -89,7 +89,8 @@
return 0;
}
- virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid)
+ virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
+ int32_t flags)
{
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
@@ -98,6 +99,7 @@
void* buf = data.writeInplace(itemLength);
memcpy(buf, item, itemLength);
data.writeInt32(uid);
+ data.writeInt32(flags);
status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply);
if (status != NO_ERROR) {
ALOGD("import() could not contact remote: %d\n", status);
@@ -268,12 +270,13 @@
return ret;
}
- virtual int32_t generate(const String16& name, int uid)
+ virtual int32_t generate(const String16& name, int uid, int32_t flags)
{
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
data.writeInt32(uid);
+ data.writeInt32(flags);
status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
if (status != NO_ERROR) {
ALOGD("generate() could not contact remote: %d\n", status);
@@ -288,7 +291,8 @@
return ret;
}
- virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength, int uid)
+ virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength, int uid,
+ int flags)
{
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
@@ -297,6 +301,7 @@
void* buf = data.writeInplace(keyLength);
memcpy(buf, key, keyLength);
data.writeInt32(uid);
+ data.writeInt32(flags);
status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply);
if (status != NO_ERROR) {
ALOGD("import() could not contact remote: %d\n", status);
@@ -593,7 +598,8 @@
inSize = 0;
}
int uid = data.readInt32();
- int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize, uid);
+ int32_t flags = data.readInt32();
+ int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize, uid, flags);
reply->writeNoException();
reply->writeInt32(ret);
return NO_ERROR;
@@ -672,7 +678,8 @@
CHECK_INTERFACE(IKeystoreService, data, reply);
String16 name = data.readString16();
int uid = data.readInt32();
- int32_t ret = generate(name, uid);
+ int32_t flags = data.readInt32();
+ int32_t ret = generate(name, uid, flags);
reply->writeNoException();
reply->writeInt32(ret);
return NO_ERROR;
@@ -689,7 +696,8 @@
inSize = 0;
}
int uid = data.readInt32();
- int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize, uid);
+ int32_t flags = data.readInt32();
+ int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize, uid, flags);
reply->writeNoException();
reply->writeInt32(ret);
return NO_ERROR;
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index 050dd5b..9b54454 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -60,7 +60,8 @@
virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) = 0;
- virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid) = 0;
+ virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
+ int32_t flags) = 0;
virtual int32_t del(const String16& name, int uid) = 0;
@@ -78,9 +79,10 @@
virtual int32_t zero() = 0;
- virtual int32_t generate(const String16& name, int uid) = 0;
+ virtual int32_t generate(const String16& name, int uid, int32_t flags) = 0;
- virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid) = 0;
+ virtual int32_t import(const String16& name, const uint8_t* data, size_t length, int uid,
+ int32_t flags) = 0;
virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
size_t* outLength) = 0;
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index c8f2755..973c447 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -43,6 +43,14 @@
SIGNATURE_INVALID = 14,
};
+/*
+ * All the flags for import and insert calls.
+ */
+enum {
+ KEYSTORE_FLAG_NONE = 0,
+ KEYSTORE_FLAG_ENCRYPTED = 1,
+};
+
/**
* Returns the size of the softkey magic header value for measuring
* and allocating purposes.
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 84f5794..5729dbd 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -364,7 +364,7 @@
* can be found in blob.length. The description is stored after the secret in
* plaintext, and its size is specified in blob.info. The total size of the two
* parts must be no more than VALUE_SIZE bytes. The first field is the version,
- * the second is the blob's type, and the third byte is reserved. Fields other
+ * the second is the blob's type, and the third byte is flags. Fields other
* than blob.info, blob.length, and blob.value are modified by encryptBlob()
* and decryptBlob(). Thus they should not be accessed from outside. */
@@ -385,7 +385,7 @@
struct __attribute__((packed)) blob {
uint8_t version;
uint8_t type;
- uint8_t reserved;
+ uint8_t flags;
uint8_t info;
uint8_t vector[AES_BLOCK_SIZE];
uint8_t encrypted[0]; // Marks offset to encrypted data.
@@ -402,7 +402,7 @@
TYPE_KEY_PAIR = 3,
} BlobType;
-static const uint8_t CURRENT_BLOB_VERSION = 1;
+static const uint8_t CURRENT_BLOB_VERSION = 2;
class Blob {
public:
@@ -416,6 +416,8 @@
mBlob.version = CURRENT_BLOB_VERSION;
mBlob.type = uint8_t(type);
+
+ mBlob.flags = KEYSTORE_FLAG_NONE;
}
Blob(blob b) {
@@ -444,6 +446,22 @@
return mBlob.version;
}
+ bool isEncrypted() const {
+ if (mBlob.version < 2) {
+ return true;
+ }
+
+ return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
+ }
+
+ void setEncrypted(bool encrypted) {
+ if (encrypted) {
+ mBlob.flags |= KEYSTORE_FLAG_ENCRYPTED;
+ } else {
+ mBlob.flags &= ~KEYSTORE_FLAG_ENCRYPTED;
+ }
+ }
+
void setVersion(uint8_t version) {
mBlob.version = version;
}
@@ -456,10 +474,18 @@
mBlob.type = uint8_t(type);
}
- ResponseCode encryptBlob(const char* filename, AES_KEY *aes_key, Entropy* entropy) {
- if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) {
- ALOGW("Could not read random data for: %s", filename);
- return SYSTEM_ERROR;
+ ResponseCode writeBlob(const char* filename, AES_KEY *aes_key, State state, Entropy* entropy) {
+ ALOGV("writing blob %s", filename);
+ if (isEncrypted()) {
+ if (state != STATE_NO_ERROR) {
+ ALOGD("couldn't insert encrypted blob while not unlocked");
+ return LOCKED;
+ }
+
+ if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) {
+ ALOGW("Could not read random data for: %s", filename);
+ return SYSTEM_ERROR;
+ }
}
// data includes the value and the value's length
@@ -475,14 +501,16 @@
memset(mBlob.value + mBlob.length, 0, digestedLength - dataLength);
mBlob.length = htonl(mBlob.length);
- MD5(mBlob.digested, digestedLength, mBlob.digest);
- uint8_t vector[AES_BLOCK_SIZE];
- memcpy(vector, mBlob.vector, AES_BLOCK_SIZE);
- AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength,
- aes_key, vector, AES_ENCRYPT);
+ if (isEncrypted()) {
+ MD5(mBlob.digested, digestedLength, mBlob.digest);
- mBlob.reserved = 0;
+ uint8_t vector[AES_BLOCK_SIZE];
+ memcpy(vector, mBlob.vector, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength,
+ aes_key, vector, AES_ENCRYPT);
+ }
+
size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
size_t fileLength = encryptedLength + headerLength + mBlob.info;
@@ -509,7 +537,8 @@
return NO_ERROR;
}
- ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) {
+ ResponseCode readBlob(const char* filename, AES_KEY *aes_key, State state) {
+ ALOGV("reading blob %s", filename);
int in = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
if (in < 0) {
return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
@@ -521,22 +550,37 @@
if (close(in) != 0) {
return SYSTEM_ERROR;
}
+
+ if (isEncrypted() && (state != STATE_NO_ERROR)) {
+ return LOCKED;
+ }
+
size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
if (fileLength < headerLength) {
return VALUE_CORRUPTED;
}
ssize_t encryptedLength = fileLength - (headerLength + mBlob.info);
- if (encryptedLength < 0 || encryptedLength % AES_BLOCK_SIZE != 0) {
+ if (encryptedLength < 0) {
return VALUE_CORRUPTED;
}
- AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key,
- mBlob.vector, AES_DECRYPT);
- size_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
- uint8_t computedDigest[MD5_DIGEST_LENGTH];
- MD5(mBlob.digested, digestedLength, computedDigest);
- if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
- return VALUE_CORRUPTED;
+
+ ssize_t digestedLength;
+ if (isEncrypted()) {
+ if (encryptedLength % AES_BLOCK_SIZE != 0) {
+ return VALUE_CORRUPTED;
+ }
+
+ AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key,
+ mBlob.vector, AES_DECRYPT);
+ digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
+ uint8_t computedDigest[MD5_DIGEST_LENGTH];
+ MD5(mBlob.digested, digestedLength, computedDigest);
+ if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
+ return VALUE_CORRUPTED;
+ }
+ } else {
+ digestedLength = encryptedLength;
}
ssize_t maxValueLength = digestedLength - sizeof(mBlob.length);
@@ -634,7 +678,7 @@
AES_KEY passwordAesKey;
AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
- return masterKeyBlob.encryptBlob(mMasterKeyFile, &passwordAesKey, entropy);
+ return masterKeyBlob.writeBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR, entropy);
}
ResponseCode readMasterKey(const android::String8& pw, Entropy* entropy) {
@@ -662,9 +706,10 @@
AES_KEY passwordAesKey;
AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
Blob masterKeyBlob(rawBlob);
- ResponseCode response = masterKeyBlob.decryptBlob(mMasterKeyFile, &passwordAesKey);
+ ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, &passwordAesKey,
+ STATE_NO_ERROR);
if (response == SYSTEM_ERROR) {
- return SYSTEM_ERROR;
+ return response;
}
if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
// if salt was missing, generate one and write a new master key file with the salt.
@@ -929,7 +974,8 @@
ResponseCode get(const char* filename, Blob* keyBlob, const BlobType type, uid_t uid) {
UserState* userState = getUserState(uid);
- ResponseCode rc = keyBlob->decryptBlob(filename, userState->getDecryptionKey());
+ ResponseCode rc = keyBlob->readBlob(filename, userState->getDecryptionKey(),
+ userState->getState());
if (rc != NO_ERROR) {
return rc;
}
@@ -942,8 +988,8 @@
*/
if (upgradeBlob(filename, keyBlob, version, type, uid)) {
if ((rc = this->put(filename, keyBlob, uid)) != NO_ERROR
- || (rc = keyBlob->decryptBlob(filename, userState->getDecryptionKey()))
- != NO_ERROR) {
+ || (rc = keyBlob->readBlob(filename, userState->getDecryptionKey(),
+ userState->getState())) != NO_ERROR) {
return rc;
}
}
@@ -959,7 +1005,8 @@
ResponseCode put(const char* filename, Blob* keyBlob, uid_t uid) {
UserState* userState = getUserState(uid);
- return keyBlob->encryptBlob(filename, userState->getEncryptionKey(), mEntropy);
+ return keyBlob->writeBlob(filename, userState->getEncryptionKey(), userState->getState(),
+ mEntropy);
}
void addGrant(const char* filename, uid_t granteeUid) {
@@ -989,7 +1036,8 @@
return getGrant(filename, uid) != NULL;
}
- ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename, uid_t uid) {
+ ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename, uid_t uid,
+ int32_t flags) {
uint8_t* data;
size_t dataLength;
int rc;
@@ -1008,6 +1056,8 @@
Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
free(data);
+ keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
return put(filename, &keyBlob, uid);
}
@@ -1154,6 +1204,15 @@
updated = true;
}
+ /* From V1 -> V2: All old keys were encrypted */
+ if (version == 1) {
+ ALOGV("upgrading to version 2");
+
+ blob->setEncrypted(true);
+ version = 2;
+ updated = true;
+ }
+
/*
* If we've updated, set the key blob to the right version
* and write it.
@@ -1200,7 +1259,8 @@
return SYSTEM_ERROR;
}
- ResponseCode rc = importKey(pkcs8key.get(), len, filename, uid);
+ ResponseCode rc = importKey(pkcs8key.get(), len, filename, uid,
+ blob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
if (rc != NO_ERROR) {
return rc;
}
@@ -1342,12 +1402,6 @@
return ::PERMISSION_DENIED;
}
- State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
- ALOGD("calling get in state: %d", state);
- return state;
- }
-
String8 name8(name);
Blob keyBlob;
@@ -1367,25 +1421,26 @@
return ::NO_ERROR;
}
- int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int targetUid) {
+ int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int targetUid,
+ int32_t flags) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!has_permission(callingUid, P_INSERT)) {
ALOGW("permission denied for %d: insert", callingUid);
return ::PERMISSION_DENIED;
}
+ State state = mKeyStore->getState(callingUid);
+ if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
+ ALOGD("calling get in state: %d", state);
+ return state;
+ }
+
if (targetUid == -1) {
targetUid = callingUid;
} else if (!is_granted_to(callingUid, targetUid)) {
return ::PERMISSION_DENIED;
}
- State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
- ALOGD("calling insert in state: %d", state);
- return state;
- }
-
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
@@ -1601,7 +1656,7 @@
return mKeyStore->isEmpty(callingUid) ? ::KEY_NOT_FOUND : ::NO_ERROR;
}
- int32_t generate(const String16& name, int targetUid) {
+ int32_t generate(const String16& name, int targetUid, int32_t flags) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!has_permission(callingUid, P_INSERT)) {
ALOGW("permission denied for %d: generate", callingUid);
@@ -1615,8 +1670,8 @@
}
State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
- ALOGD("calling generate in state: %d", state);
+ if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
+ ALOGW("calling generate in state: %d", state);
return state;
}
@@ -1651,7 +1706,8 @@
return mKeyStore->put(filename.string(), &keyBlob, callingUid);
}
- int32_t import(const String16& name, const uint8_t* data, size_t length, int targetUid) {
+ int32_t import(const String16& name, const uint8_t* data, size_t length, int targetUid,
+ int32_t flags) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!has_permission(callingUid, P_INSERT)) {
ALOGW("permission denied for %d: import", callingUid);
@@ -1665,7 +1721,7 @@
}
State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
+ if ((flags & KEYSTORE_FLAG_ENCRYPTED) && !isKeystoreUnlocked(state)) {
ALOGD("calling import in state: %d", state);
return state;
}
@@ -1673,7 +1729,7 @@
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
- return mKeyStore->importKey(data, length, filename.string(), callingUid);
+ return mKeyStore->importKey(data, length, filename.string(), callingUid, flags);
}
int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
@@ -1684,12 +1740,6 @@
return ::PERMISSION_DENIED;
}
- State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
- ALOGD("calling sign in state: %d", state);
- return state;
- }
-
Blob keyBlob;
String8 name8(name);
@@ -1791,12 +1841,6 @@
return ::PERMISSION_DENIED;
}
- State state = mKeyStore->getState(callingUid);
- if (!isKeystoreUnlocked(state)) {
- ALOGD("calling get_pubkey in state: %d", state);
- return state;
- }
-
Blob keyBlob;
String8 name8(name);
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index fc501bf..1e19890 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -208,7 +208,7 @@
NO_ARG_INT_RETURN(zero);
- SINGLE_ARG_PLUS_UID_INT_RETURN(generate);
+ // TODO: generate
SINGLE_ARG_DATA_RETURN(get_pubkey);