diff options
author | Shawn Willden <swillden@google.com> | 2016-01-21 12:41:23 -0700 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2016-01-27 20:25:38 -0700 |
commit | 50eb1b2f89ca455b2e9caa635bfe0b5ed94b416a (patch) | |
tree | f6bf4b89bc812d9561e1055296f0a145976839e5 | |
parent | fd50293cd5f91936ea954b0556f3f434243adf27 (diff) | |
download | security-50eb1b2f89ca455b2e9caa635bfe0b5ed94b416a.tar.gz |
Add attestation support to keystore.
Bug: 22914603
Change-Id: I14fbfbe30b96c5c29278fa548e06b65f15942fe2
-rw-r--r-- | keystore/IKeystoreService.cpp | 111 | ||||
-rw-r--r-- | keystore/include/keystore/IKeystoreService.h | 14 | ||||
-rw-r--r-- | keystore/key_store_service.cpp | 34 | ||||
-rw-r--r-- | keystore/key_store_service.h | 3 |
4 files changed, 145 insertions, 17 deletions
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp index 8ed09c4c..466ac241 100644 --- a/keystore/IKeystoreService.cpp +++ b/keystore/IKeystoreService.cpp @@ -208,6 +208,69 @@ void KeyCharacteristics::writeToParcel(Parcel* out) const { } } +KeymasterCertificateChain::KeymasterCertificateChain() { + memset(&chain, 0, sizeof(chain)); +} + +KeymasterCertificateChain::~KeymasterCertificateChain() { + keymaster_free_cert_chain(&chain); +} + +static bool readKeymasterBlob(const Parcel& in, keymaster_blob_t* blob) { + if (in.readInt32() != 1) { + return false; + } + + blob->data_length = 0; + ssize_t length = in.readInt32(); + if (length <= 0) { + blob->data = nullptr; + return false; + } + + blob->data = reinterpret_cast<const uint8_t*>(in.readInplace(length)); + if (blob->data) { + blob->data_length = static_cast<size_t>(length); + } + return true; +} + +void KeymasterCertificateChain::readFromParcel(const Parcel& in) { + ssize_t count = in.readInt32(); + size_t ucount = count; + if (count < 0) { + ucount = 0; + } + keymaster_free_cert_chain(&chain); + chain.entries = new keymaster_blob_t[ucount]; + memset(chain.entries, 0, sizeof(keymaster_blob_t) * ucount); + for (size_t i = 0; i < ucount; ++i) { + if (!readKeymasterBlob(in, &chain.entries[i])) { + keymaster_free_cert_chain(&chain); + return; + } + } +} + +void KeymasterCertificateChain::writeToParcel(Parcel* out) const { + out->writeInt32(chain.entry_count); + for (size_t i = 0; i < chain.entry_count; ++i) { + if (chain.entries[i].data) { + out->writeInt32(1); // Tell Java side that object is not NULL + out->writeInt32(chain.entries[i].data_length); + void* buf = out->writeInplace(chain.entries[i].data_length); + if (buf) { + memcpy(buf, chain.entries[i].data, chain.entries[i].data_length); + } else { + ALOGE("Failed to writeInplace keymaster cert chain entry"); + } + } else { + out->writeInt32(0); // Tell Java side this object is NULL. + ALOGE("Found NULL certificate chain entry"); + } + } +} + void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out) { switch (keymaster_tag_get_type(param.tag)) { case KM_ENUM: @@ -369,23 +432,9 @@ err: } static std::unique_ptr<keymaster_blob_t> readKeymasterBlob(const Parcel& in) { - std::unique_ptr<keymaster_blob_t> blob; - if (in.readInt32() != 1) { - blob.reset(NULL); - return blob; - } - ssize_t length = in.readInt32(); - blob.reset(new keymaster_blob_t); - if (length > 0) { - blob->data = reinterpret_cast<const uint8_t*>(in.readInplace(length)); - if (blob->data) { - blob->data_length = static_cast<size_t>(length); - } else { - blob->data_length = 0; - } - } else { - blob->data = NULL; - blob->data_length = 0; + std::unique_ptr<keymaster_blob_t> blob (new keymaster_blob_t); + if (!readKeymasterBlob(in, blob.get())) { + blob.reset(); } return blob; } @@ -1257,6 +1306,34 @@ public: return ret; } + virtual int32_t attestKey(const String16& name, const KeymasterArguments& params, + KeymasterCertificateChain* outChain) { + if (!outChain) + return KM_ERROR_OUTPUT_PARAMETER_NULL; + + Parcel data, reply; + data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); + data.writeString16(name); + data.writeInt32(1); // params is not NULL. + params.writeToParcel(&data); + + status_t status = remote()->transact(BnKeystoreService::ATTEST_KEY, data, &reply); + if (status != NO_ERROR) { + ALOGD("attestkey() count not contact remote: %d\n", status); + return KM_ERROR_UNKNOWN_ERROR; + } + int32_t err = reply.readExceptionCode(); + int32_t ret = reply.readInt32(); + if (err < 0) { + ALOGD("attestKey() caught exception %d\n", err); + return KM_ERROR_UNKNOWN_ERROR; + } + if (reply.readInt32() != 0) { + outChain->readFromParcel(reply); + } + return ret; + } + }; IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService"); diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h index c136dfd0..1c2f6a58 100644 --- a/keystore/include/keystore/IKeystoreService.h +++ b/keystore/include/keystore/IKeystoreService.h @@ -90,6 +90,16 @@ struct KeyCharacteristics { keymaster_key_characteristics_t characteristics; }; +// struct for serializing keymaster_cert_chain_t's +struct KeymasterCertificateChain { + KeymasterCertificateChain(); + ~KeymasterCertificateChain(); + void readFromParcel(const Parcel& in); + void writeToParcel(Parcel* out) const; + + keymaster_cert_chain_t chain; +}; + bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out); void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out); @@ -134,6 +144,7 @@ public: ADD_AUTH_TOKEN = IBinder::FIRST_CALL_TRANSACTION + 32, ON_USER_ADDED = IBinder::FIRST_CALL_TRANSACTION + 33, ON_USER_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 34, + ATTEST_KEY = IBinder::FIRST_CALL_TRANSACTION + 35, }; DECLARE_META_INTERFACE(KeystoreService); @@ -231,6 +242,9 @@ public: virtual int32_t onUserRemoved(int32_t userId) = 0; + virtual int32_t attestKey(const String16& name, const KeymasterArguments& params, + KeymasterCertificateChain* outChain) = 0; + }; // ---------------------------------------------------------------------------- diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp index 9fbb6bc6..759ef06a 100644 --- a/keystore/key_store_service.cpp +++ b/keystore/key_store_service.cpp @@ -1076,6 +1076,40 @@ int32_t KeyStoreService::addAuthToken(const uint8_t* token, size_t length) { return ::NO_ERROR; } +int32_t KeyStoreService::attestKey(const String16& name, const KeymasterArguments& params, + KeymasterCertificateChain* outChain) { + if (!outChain) + return KM_ERROR_OUTPUT_PARAMETER_NULL; + + if (!checkAllowedOperationParams(params.params)) { + return KM_ERROR_INVALID_ARGUMENT; + } + + uid_t callingUid = IPCThreadState::self()->getCallingUid(); + + Blob keyBlob; + String8 name8(name); + ResponseCode responseCode = + mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10); + if (responseCode != ::NO_ERROR) { + return responseCode; + } + + keymaster_key_blob_t key = {keyBlob.getValue(), + static_cast<size_t>(std::max(0, keyBlob.getLength()))}; + auto* dev = mKeyStore->getDeviceForBlob(keyBlob); + if (!dev->attest_key) + return KM_ERROR_UNIMPLEMENTED; + + const keymaster_key_param_set_t in_params = { + const_cast<keymaster_key_param_t*>(params.params.data()), params.params.size()}; + outChain->chain = {nullptr, 0}; + int32_t rc = dev->attest_key(dev, &key, &in_params, &outChain->chain); + if (rc) + return rc; + return ::NO_ERROR; +} + /** * Prune the oldest pruneable operation. */ diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h index e61bdea1..35b89289 100644 --- a/keystore/key_store_service.h +++ b/keystore/key_store_service.h @@ -114,6 +114,9 @@ class KeyStoreService : public BnKeystoreService, public IBinder::DeathRecipient int32_t addAuthToken(const uint8_t* token, size_t length); + int32_t attestKey(const String16& name, const KeymasterArguments& params, + KeymasterCertificateChain* outChain) override; + private: static const int32_t UID_SELF = -1; |