/* * Copyright (C) 2011 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 // For debugging #define LOG_NDEBUG 0 // TEE is the Trusted Execution Environment #define LOG_TAG "TEEKeyMaster" #include #include #include #include #include #include #include #include #include #include #include /** The size of a key ID in bytes */ #define ID_LENGTH 32 /** The current stored key version. */ const static uint32_t KEY_VERSION = 1; struct EVP_PKEY_Delete { void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); } }; typedef UniquePtr Unique_EVP_PKEY; struct RSA_Delete { void operator()(RSA* p) const { RSA_free(p); } }; typedef UniquePtr Unique_RSA; struct PKCS8_PRIV_KEY_INFO_Delete { void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); } }; typedef UniquePtr Unique_PKCS8_PRIV_KEY_INFO; typedef UniquePtr Unique_keymaster_device_t; typedef UniquePtr Unique_CK_BYTE; typedef UniquePtr Unique_CK_ATTRIBUTE; class ByteArray { public: ByteArray(CK_BYTE* array, size_t len) : mArray(array), mLength(len) { } ByteArray(size_t len) : mLength(len) { mArray = new CK_BYTE[len]; } ~ByteArray() { if (mArray != NULL) { delete[] mArray; } } CK_BYTE* get() const { return mArray; } size_t length() const { return mLength; } CK_BYTE* release() { CK_BYTE* array = mArray; mArray = NULL; return array; } private: CK_BYTE* mArray; size_t mLength; }; typedef UniquePtr Unique_ByteArray; class CryptoSession { public: CryptoSession(CK_SESSION_HANDLE masterHandle) : mHandle(masterHandle), mSubsession(CK_INVALID_HANDLE) { CK_SESSION_HANDLE subsessionHandle = mHandle; CK_RV openSessionRV = C_OpenSession(CKV_TOKEN_USER, CKF_SERIAL_SESSION | CKF_RW_SESSION | CKVF_OPEN_SUB_SESSION, NULL, NULL, &subsessionHandle); if (openSessionRV != CKR_OK || subsessionHandle == CK_INVALID_HANDLE) { (void) C_Finalize(NULL_PTR); ALOGE("Error opening secondary session with TEE: 0x%x", openSessionRV); } else { ALOGV("Opening subsession 0x%x", subsessionHandle); mSubsession = subsessionHandle; } } ~CryptoSession() { if (mSubsession != CK_INVALID_HANDLE) { CK_RV rv = C_CloseSession(mSubsession); ALOGV("Closing subsession 0x%x: 0x%x", mSubsession, rv); mSubsession = CK_INVALID_HANDLE; } } CK_SESSION_HANDLE get() const { return mSubsession; } CK_SESSION_HANDLE getPrimary() const { return mHandle; } private: CK_SESSION_HANDLE mHandle; CK_SESSION_HANDLE mSubsession; }; class ObjectHandle { public: ObjectHandle(const CryptoSession* session, CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE) : mSession(session), mHandle(handle) { } ~ObjectHandle() { if (mHandle != CK_INVALID_HANDLE) { CK_RV rv = C_CloseObjectHandle(mSession->getPrimary(), mHandle); if (rv != CKR_OK) { ALOGW("Couldn't close object handle 0x%x: 0x%x", mHandle, rv); } else { ALOGV("Closing object handle 0x%x", mHandle); mHandle = CK_INVALID_HANDLE; } } } CK_OBJECT_HANDLE get() const { return mHandle; } void reset(CK_OBJECT_HANDLE handle) { mHandle = handle; } private: const CryptoSession* mSession; CK_OBJECT_HANDLE mHandle; }; /** * Many OpenSSL APIs take ownership of an argument on success but don't free the argument * on failure. This means we need to tell our scoped pointers when we've transferred ownership, * without triggering a warning by not using the result of release(). */ #define OWNERSHIP_TRANSFERRED(obj) \ typeof (obj.release()) _dummy __attribute__((unused)) = obj.release() /* * Checks this thread's OpenSSL error queue and logs if * necessary. */ static void logOpenSSLError(const char* location) { int error = ERR_get_error(); if (error != 0) { char message[256]; ERR_error_string_n(error, message, sizeof(message)); ALOGE("OpenSSL error in %s %d: %s", location, error, message); } ERR_clear_error(); ERR_remove_state(0); } /** * Convert from OpenSSL's BIGNUM format to TEE's Big Integer format. */ static ByteArray* bignum_to_array(const BIGNUM* bn) { const int bignumSize = BN_num_bytes(bn); Unique_CK_BYTE bytes(new CK_BYTE[bignumSize]); unsigned char* tmp = reinterpret_cast(bytes.get()); if (BN_bn2bin(bn, tmp) != bignumSize) { ALOGE("public exponent size wasn't what was expected"); return NULL; } return new ByteArray(bytes.release(), bignumSize); } static void set_attribute(CK_ATTRIBUTE* attrib, CK_ATTRIBUTE_TYPE type, void* pValue, CK_ULONG ulValueLen) { attrib->type = type; attrib->pValue = pValue; attrib->ulValueLen = ulValueLen; } static ByteArray* generate_random_id() { Unique_ByteArray id(new ByteArray(ID_LENGTH)); if (RAND_pseudo_bytes(reinterpret_cast(id->get()), id->length()) < 0) { return NULL; } return id.release(); } static int keyblob_save(ByteArray* objId, uint8_t** key_blob, size_t* key_blob_length) { Unique_ByteArray handleBlob(new ByteArray(sizeof(uint32_t) + objId->length())); if (handleBlob.get() == NULL) { ALOGE("Could not allocate key blob"); return -1; } uint8_t* tmp = handleBlob->get(); for (size_t i = 0; i < sizeof(uint32_t); i++) { *tmp++ = KEY_VERSION >> ((sizeof(uint32_t) - i - 1) * 8); } memcpy(tmp, objId->get(), objId->length()); *key_blob_length = handleBlob->length(); *key_blob = handleBlob->get(); ByteArray* unused __attribute__((unused)) = handleBlob.release(); return 0; } static int find_single_object(const uint8_t* obj_id, const size_t obj_id_length, CK_OBJECT_CLASS obj_class, const CryptoSession* session, ObjectHandle* object) { // Note that the CKA_ID attribute is never written, so we can cast away const here. void* obj_id_ptr = reinterpret_cast(const_cast(obj_id)); CK_ATTRIBUTE attributes[] = { { CKA_ID, obj_id_ptr, obj_id_length }, { CKA_CLASS, &obj_class, sizeof(obj_class) }, }; CK_RV rv = C_FindObjectsInit(session->get(), attributes, sizeof(attributes) / sizeof(CK_ATTRIBUTE)); if (rv != CKR_OK) { ALOGE("Error in C_FindObjectsInit: 0x%x", rv); return -1; } CK_OBJECT_HANDLE tmpHandle; CK_ULONG tmpCount; rv = C_FindObjects(session->get(), &tmpHandle, 1, &tmpCount); ALOGV("Found %d object 0x%x : class 0x%x", tmpCount, tmpHandle, obj_class); if (rv != CKR_OK || tmpCount != 1) { C_FindObjectsFinal(session->get()); ALOGE("Couldn't find key!"); return -1; } C_FindObjectsFinal(session->get()); object->reset(tmpHandle); return 0; } static int keyblob_restore(const CryptoSession* session, const uint8_t* keyBlob, const size_t keyBlobLength, ObjectHandle* public_key, ObjectHandle* private_key) { if (keyBlob == NULL) { ALOGE("key blob was null"); return -1; } if (keyBlobLength < (sizeof(KEY_VERSION) + ID_LENGTH)) { ALOGE("key blob is not correct size"); return -1; } uint32_t keyVersion = 0; const uint8_t* p = keyBlob; for (size_t i = 0; i < sizeof(keyVersion); i++) { keyVersion = (keyVersion << 8) | *p++; } if (keyVersion != 1) { ALOGE("Invalid key version %d", keyVersion); return -1; } return find_single_object(p, ID_LENGTH, CKO_PUBLIC_KEY, session, public_key) || find_single_object(p, ID_LENGTH, CKO_PRIVATE_KEY, session, private_key); } static int tee_generate_keypair(const keymaster_device_t* dev, const keymaster_keypair_t type, const void* key_params, uint8_t** key_blob, size_t* key_blob_length) { CK_BBOOL bTRUE = CK_TRUE; if (type != TYPE_RSA) { ALOGW("Unknown key type %d", type); return -1; } if (key_params == NULL) { ALOGW("generate_keypair params were NULL"); return -1; } keymaster_rsa_keygen_params_t* rsa_params = (keymaster_rsa_keygen_params_t*) key_params; CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0, }; CK_ULONG modulusBits = (CK_ULONG) rsa_params->modulus_size; /** * Convert our unsigned 64-bit integer to the TEE Big Integer class. It's * an unsigned array of bytes with MSB first. */ CK_BYTE publicExponent[sizeof(uint64_t)]; const uint64_t exp = rsa_params->public_exponent; size_t offset = sizeof(publicExponent) - 1; for (size_t i = 0; i < sizeof(publicExponent); i++) { publicExponent[offset--] = (exp >> (i * CHAR_BIT)) & 0xFF; } Unique_ByteArray objId(generate_random_id()); if (objId.get() == NULL) { ALOGE("Couldn't generate random key ID"); return -1; } CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ID, objId->get(), objId->length()}, {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, {CKA_ENCRYPT, &bTRUE, sizeof(bTRUE)}, {CKA_VERIFY, &bTRUE, sizeof(bTRUE)}, {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_ID, objId->get(), objId->length()}, {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, {CKA_DECRYPT, &bTRUE, sizeof(bTRUE)}, {CKA_SIGN, &bTRUE, sizeof(bTRUE)}, }; CryptoSession session(reinterpret_cast(dev->context)); CK_OBJECT_HANDLE hPublicKey, hPrivateKey; CK_RV rv = C_GenerateKeyPair(session.get(), &mechanism, publicKeyTemplate, sizeof(publicKeyTemplate)/sizeof(CK_ATTRIBUTE), privateKeyTemplate, sizeof(privateKeyTemplate)/sizeof(CK_ATTRIBUTE), &hPublicKey, &hPrivateKey); if (rv != CKR_OK) { ALOGE("Generate keypair failed: 0x%x", rv); return -1; } ObjectHandle publicKey(&session, hPublicKey); ObjectHandle privateKey(&session, hPrivateKey); ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); return keyblob_save(objId.get(), key_blob, key_blob_length); } static int tee_import_keypair(const keymaster_device_t* dev, const uint8_t* key, const size_t key_length, uint8_t** key_blob, size_t* key_blob_length) { CK_RV rv; CK_BBOOL bTRUE = CK_TRUE; if (key == NULL) { ALOGW("provided key is null"); return -1; } Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length)); if (pkcs8.get() == NULL) { logOpenSSLError("tee_import_keypair"); return -1; } /* assign to EVP */ Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); if (pkey.get() == NULL) { logOpenSSLError("tee_import_keypair"); return -1; } if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { ALOGE("Unsupported key type: %d", EVP_PKEY_type(pkey->type)); return -1; } Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey.get())); if (rsa.get() == NULL) { logOpenSSLError("tee_import_keypair"); return -1; } Unique_ByteArray modulus(bignum_to_array(rsa->n)); if (modulus.get() == NULL) { ALOGW("Could not convert modulus to array"); return -1; } Unique_ByteArray publicExponent(bignum_to_array(rsa->e)); if (publicExponent.get() == NULL) { ALOGW("Could not convert publicExponent to array"); return -1; } CK_KEY_TYPE rsaType = CKK_RSA; CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; Unique_ByteArray objId(generate_random_id()); if (objId.get() == NULL) { ALOGE("Couldn't generate random key ID"); return -1; } CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ID, objId->get(), objId->length()}, {CKA_TOKEN, &bTRUE, sizeof(bTRUE)}, {CKA_CLASS, &pubClass, sizeof(pubClass)}, {CKA_KEY_TYPE, &rsaType, sizeof(rsaType)}, {CKA_ENCRYPT, &bTRUE, sizeof(bTRUE)}, {CKA_VERIFY, &bTRUE, sizeof(bTRUE)}, {CKA_MODULUS, modulus->get(), modulus->length()}, {CKA_PUBLIC_EXPONENT, publicExponent->get(), publicExponent->length()}, }; CryptoSession session(reinterpret_cast(dev->context)); CK_OBJECT_HANDLE hPublicKey; rv = C_CreateObject(session.get(), publicKeyTemplate, sizeof(publicKeyTemplate)/sizeof(CK_ATTRIBUTE), &hPublicKey); if (rv != CKR_OK) { ALOGE("Creation of public key failed: 0x%x", rv); return -1; } ObjectHandle publicKey(&session, hPublicKey); Unique_ByteArray privateExponent(bignum_to_array(rsa->d)); if (privateExponent.get() == NULL) { ALOGW("Could not convert private exponent"); return -1; } /* * Normally we need: * CKA_ID * CKA_TOKEN * CKA_CLASS * CKA_KEY_TYPE * * CKA_DECRYPT * CKA_SIGN * * CKA_MODULUS * CKA_PUBLIC_EXPONENT * CKA_PRIVATE_EXPONENT */ #define PRIV_ATTRIB_NORMAL_NUM (4 + 2 + 3) /* * For additional private key values: * CKA_PRIME_1 * CKA_PRIME_2 * * CKA_EXPONENT_1 * CKA_EXPONENT_2 * * CKA_COEFFICIENT */ #define PRIV_ATTRIB_EXTENDED_NUM (PRIV_ATTRIB_NORMAL_NUM + 5) /* * If we have the prime, prime exponents, and coefficient, we can * copy them in. */ bool has_extra_data = (rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && (rsa->dmq1 != NULL) && (rsa->iqmp != NULL); Unique_CK_ATTRIBUTE privateKeyTemplate(new CK_ATTRIBUTE[ has_extra_data ? PRIV_ATTRIB_EXTENDED_NUM : PRIV_ATTRIB_NORMAL_NUM]); CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; size_t templateOffset = 0; set_attribute(&privateKeyTemplate[templateOffset++], CKA_ID, objId->get(), objId->length()); set_attribute(&privateKeyTemplate[templateOffset++], CKA_TOKEN, &bTRUE, sizeof(bTRUE)); set_attribute(&privateKeyTemplate[templateOffset++], CKA_CLASS, &privClass, sizeof(privClass)); set_attribute(&privateKeyTemplate[templateOffset++], CKA_KEY_TYPE, &rsaType, sizeof(rsaType)); set_attribute(&privateKeyTemplate[templateOffset++], CKA_DECRYPT, &bTRUE, sizeof(bTRUE)); set_attribute(&privateKeyTemplate[templateOffset++], CKA_SIGN, &bTRUE, sizeof(bTRUE)); set_attribute(&privateKeyTemplate[templateOffset++], CKA_MODULUS, modulus->get(), modulus->length()); set_attribute(&privateKeyTemplate[templateOffset++], CKA_PUBLIC_EXPONENT, publicExponent->get(), publicExponent->length()); set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIVATE_EXPONENT, privateExponent->get(), privateExponent->length()); Unique_ByteArray prime1, prime2, exp1, exp2, coeff; if (has_extra_data) { prime1.reset(bignum_to_array(rsa->p)); if (prime1->get() == NULL) { ALOGW("Could not convert prime1"); return -1; } set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIME_1, prime1->get(), prime1->length()); prime2.reset(bignum_to_array(rsa->q)); if (prime2->get() == NULL) { ALOGW("Could not convert prime2"); return -1; } set_attribute(&privateKeyTemplate[templateOffset++], CKA_PRIME_2, prime2->get(), prime2->length()); exp1.reset(bignum_to_array(rsa->dmp1)); if (exp1->get() == NULL) { ALOGW("Could not convert exponent 1"); return -1; } set_attribute(&privateKeyTemplate[templateOffset++], CKA_EXPONENT_1, exp1->get(), exp1->length()); exp2.reset(bignum_to_array(rsa->dmq1)); if (exp2->get() == NULL) { ALOGW("Could not convert exponent 2"); return -1; } set_attribute(&privateKeyTemplate[templateOffset++], CKA_EXPONENT_2, exp2->get(), exp2->length()); coeff.reset(bignum_to_array(rsa->iqmp)); if (coeff->get() == NULL) { ALOGW("Could not convert coefficient"); return -1; } set_attribute(&privateKeyTemplate[templateOffset++], CKA_COEFFICIENT, coeff->get(), coeff->length()); } CK_OBJECT_HANDLE hPrivateKey; rv = C_CreateObject(session.get(), privateKeyTemplate.get(), templateOffset, &hPrivateKey); if (rv != CKR_OK) { ALOGE("Creation of private key failed: 0x%x", rv); return -1; } ObjectHandle privateKey(&session, hPrivateKey); ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); return keyblob_save(objId.get(), key_blob, key_blob_length); } static int tee_get_keypair_public(const struct keymaster_device* dev, const uint8_t* key_blob, const size_t key_blob_length, uint8_t** x509_data, size_t* x509_data_length) { CryptoSession session(reinterpret_cast(dev->context)); ObjectHandle publicKey(&session); ObjectHandle privateKey(&session); if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { return -1; } if (x509_data == NULL || x509_data_length == NULL) { ALOGW("Provided destination variables were null"); return -1; } CK_ATTRIBUTE attributes[] = { {CKA_MODULUS, NULL, 0}, {CKA_PUBLIC_EXPONENT, NULL, 0}, }; // Call first to get the sizes of the values. CK_RV rv = C_GetAttributeValue(session.get(), publicKey.get(), attributes, sizeof(attributes)/sizeof(CK_ATTRIBUTE)); if (rv != CKR_OK) { ALOGW("Could not query attribute value sizes: 0x%02x", rv); return -1; } ByteArray modulus(new CK_BYTE[attributes[0].ulValueLen], attributes[0].ulValueLen); ByteArray exponent(new CK_BYTE[attributes[1].ulValueLen], attributes[1].ulValueLen); attributes[0].pValue = modulus.get(); attributes[1].pValue = exponent.get(); rv = C_GetAttributeValue(session.get(), publicKey.get(), attributes, sizeof(attributes) / sizeof(CK_ATTRIBUTE)); if (rv != CKR_OK) { ALOGW("Could not query attribute values: 0x%02x", rv); return -1; } ALOGV("modulus is %d, exponent is %d", modulus.length(), exponent.length()); Unique_RSA rsa(RSA_new()); if (rsa.get() == NULL) { ALOGE("Could not allocate RSA structure"); return -1; } rsa->n = BN_bin2bn(reinterpret_cast(modulus.get()), modulus.length(), NULL); if (rsa->n == NULL) { logOpenSSLError("tee_get_keypair_public"); return -1; } rsa->e = BN_bin2bn(reinterpret_cast(exponent.get()), exponent.length(), NULL); if (rsa->e == NULL) { logOpenSSLError("tee_get_keypair_public"); return -1; } Unique_EVP_PKEY pkey(EVP_PKEY_new()); if (pkey.get() == NULL) { ALOGE("Could not allocate EVP_PKEY structure"); return -1; } if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { logOpenSSLError("tee_get_keypair_public"); return -1; } OWNERSHIP_TRANSFERRED(rsa); int len = i2d_PUBKEY(pkey.get(), NULL); if (len <= 0) { logOpenSSLError("tee_get_keypair_public"); return -1; } UniquePtr key(static_cast(malloc(len))); if (key.get() == NULL) { ALOGE("Could not allocate memory for public key data"); return -1; } unsigned char* tmp = reinterpret_cast(key.get()); if (i2d_PUBKEY(pkey.get(), &tmp) != len) { logOpenSSLError("tee_get_keypair_public"); return -1; } ALOGV("Length of x509 data is %d", len); *x509_data_length = len; *x509_data = key.release(); return 0; } static int tee_delete_keypair(const struct keymaster_device* dev, const uint8_t* key_blob, const size_t key_blob_length) { CryptoSession session(reinterpret_cast(dev->context)); ObjectHandle publicKey(&session); ObjectHandle privateKey(&session); if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { return -1; } // Delete the private key. CK_RV rv = C_DestroyObject(session.get(), privateKey.get()); if (rv != CKR_OK) { ALOGW("Could destroy private key object: 0x%02x", rv); return -1; } // Delete the public key. rv = C_DestroyObject(session.get(), publicKey.get()); if (rv != CKR_OK) { ALOGW("Could destroy public key object: 0x%02x", rv); return -1; } return 0; } static int tee_sign_data(const keymaster_device_t* dev, const void* params, const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data, const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { ALOGV("tee_sign_data(%p, %p, %llu, %p, %llu, %p, %p)", dev, key_blob, (unsigned long long) key_blob_length, data, (unsigned long long) dataLength, signedData, signedDataLength); if (params == NULL) { ALOGW("Signing params were null"); return -1; } CryptoSession session(reinterpret_cast(dev->context)); ObjectHandle publicKey(&session); ObjectHandle privateKey(&session); if (keyblob_restore(&session, key_blob, key_blob_length, &publicKey, &privateKey)) { return -1; } ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; if (sign_params->digest_type != DIGEST_NONE) { ALOGW("Cannot handle digest type %d", sign_params->digest_type); return -1; } else if (sign_params->padding_type != PADDING_NONE) { ALOGW("Cannot handle padding type %d", sign_params->padding_type); return -1; } CK_MECHANISM rawRsaMechanism = { CKM_RSA_X_509, NULL, 0 }; CK_RV rv = C_SignInit(session.get(), &rawRsaMechanism, privateKey.get()); if (rv != CKR_OK) { ALOGV("C_SignInit failed: 0x%x", rv); return -1; } CK_BYTE signature[1024]; CK_ULONG signatureLength = 1024; rv = C_Sign(session.get(), data, dataLength, signature, &signatureLength); if (rv != CKR_OK) { ALOGV("C_SignFinal failed: 0x%x", rv); return -1; } UniquePtr finalSignature(new uint8_t[signatureLength]); if (finalSignature.get() == NULL) { ALOGE("Couldn't allocate memory to copy signature"); return -1; } memcpy(finalSignature.get(), signature, signatureLength); *signedData = finalSignature.release(); *signedDataLength = static_cast(signatureLength); ALOGV("tee_sign_data(%p, %p, %llu, %p, %llu, %p, %p) => %p size %llu", dev, key_blob, (unsigned long long) key_blob_length, data, (unsigned long long) dataLength, signedData, signedDataLength, *signedData, (unsigned long long) *signedDataLength); return 0; } static int tee_verify_data(const keymaster_device_t* dev, const void* params, const uint8_t* keyBlob, const size_t keyBlobLength, const uint8_t* signedData, const size_t signedDataLength, const uint8_t* signature, const size_t signatureLength) { ALOGV("tee_verify_data(%p, %p, %llu, %p, %llu, %p, %llu)", dev, keyBlob, (unsigned long long) keyBlobLength, signedData, (unsigned long long) signedDataLength, signature, (unsigned long long) signatureLength); if (params == NULL) { ALOGW("Verification params were null"); return -1; } CryptoSession session(reinterpret_cast(dev->context)); ObjectHandle publicKey(&session); ObjectHandle privateKey(&session); if (keyblob_restore(&session, keyBlob, keyBlobLength, &publicKey, &privateKey)) { return -1; } ALOGV("public handle = 0x%x, private handle = 0x%x", publicKey.get(), privateKey.get()); keymaster_rsa_sign_params_t* sign_params = (keymaster_rsa_sign_params_t*) params; if (sign_params->digest_type != DIGEST_NONE) { ALOGW("Cannot handle digest type %d", sign_params->digest_type); return -1; } else if (sign_params->padding_type != PADDING_NONE) { ALOGW("Cannot handle padding type %d", sign_params->padding_type); return -1; } CK_MECHANISM rawRsaMechanism = { CKM_RSA_X_509, NULL, 0 }; CK_RV rv = C_VerifyInit(session.get(), &rawRsaMechanism, publicKey.get()); if (rv != CKR_OK) { ALOGV("C_VerifyInit failed: 0x%x", rv); return -1; } // This is a bad prototype for this function. C_Verify should have only const args. rv = C_Verify(session.get(), signedData, signedDataLength, const_cast(signature), signatureLength); if (rv != CKR_OK) { ALOGV("C_Verify failed: 0x%x", rv); return -1; } return 0; } /* Close an opened OpenSSL instance */ static int tee_close(hw_device_t *dev) { keymaster_device_t *keymaster_dev = (keymaster_device_t *) dev; if (keymaster_dev != NULL) { CK_SESSION_HANDLE handle = reinterpret_cast(keymaster_dev->context); if (handle != CK_INVALID_HANDLE) { C_CloseSession(handle); } } CK_RV finalizeRV = C_Finalize(NULL_PTR); if (finalizeRV != CKR_OK) { ALOGE("Error closing the TEE"); } free(dev); return 0; } /* * Generic device handling */ static int tee_open(const hw_module_t* module, const char* name, hw_device_t** device) { if (strcmp(name, KEYSTORE_KEYMASTER) != 0) return -EINVAL; Unique_keymaster_device_t dev(new keymaster_device_t); if (dev.get() == NULL) return -ENOMEM; dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 1; dev->common.module = (struct hw_module_t*) module; dev->common.close = tee_close; dev->generate_keypair = tee_generate_keypair; dev->import_keypair = tee_import_keypair; dev->get_keypair_public = tee_get_keypair_public; dev->delete_keypair = tee_delete_keypair; dev->sign_data = tee_sign_data; dev->verify_data = tee_verify_data; dev->delete_all = NULL; CK_RV initializeRV = C_Initialize(NULL); if (initializeRV != CKR_OK) { ALOGE("Error initializing TEE: 0x%x", initializeRV); return -ENODEV; } CK_INFO info; CK_RV infoRV = C_GetInfo(&info); if (infoRV != CKR_OK) { (void) C_Finalize(NULL_PTR); ALOGE("Error getting information about TEE during initialization: 0x%x", infoRV); return -ENODEV; } ALOGI("C_GetInfo cryptokiVer=%d.%d manufID=%s flags=%d libDesc=%s libVer=%d.%d\n", info.cryptokiVersion.major, info.cryptokiVersion.minor, info.manufacturerID, info.flags, info.libraryDescription, info.libraryVersion.major, info.libraryVersion.minor); CK_SESSION_HANDLE sessionHandle = CK_INVALID_HANDLE; CK_RV openSessionRV = C_OpenSession(CKV_TOKEN_USER, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &sessionHandle); if (openSessionRV != CKR_OK || sessionHandle == CK_INVALID_HANDLE) { (void) C_Finalize(NULL_PTR); ALOGE("Error opening primary session with TEE: 0x%x", openSessionRV); return -1; } ERR_load_crypto_strings(); ERR_load_BIO_strings(); dev->context = reinterpret_cast(sessionHandle); *device = reinterpret_cast(dev.release()); return 0; } static struct hw_module_methods_t keystore_module_methods = { open: tee_open, }; struct keystore_module HAL_MODULE_INFO_SYM __attribute__ ((visibility ("default"))) = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: KEYSTORE_HARDWARE_MODULE_ID, name: "Keymaster TEE HAL", author: "The Android Open Source Project", methods: &keystore_module_methods, dso: 0, reserved: {}, }, };