/* * Copyright 2015 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 #include #include #include #include #include #include #include namespace keymaster { namespace { constexpr uint8_t kAesGcmDescriptor1[] = "AES-256-GCM-HKDF-SHA-256, version 1"; constexpr uint8_t kAesGcmDescriptor2[] = "AES-256-GCM-HKDF-SHA-256, version 2"; constexpr size_t kAesGcmNonceLength = 12; constexpr size_t kAesGcmTagLength = 16; constexpr size_t kAes256KeyLength = 256 / 8; KmErrorOr generate_nonce(const RandomSource& random, size_t size) { Buffer nonce; if (!nonce.Reinitialize(size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; random.GenerateRandom(nonce.peek_write(), size); nonce.advance_write(size); return nonce; } KmErrorOr BuildDerivationInfo(const AuthEncryptedBlobFormat format, // const AuthorizationSet& hw_enforced, // const AuthorizationSet& sw_enforced, // const AuthorizationSet& hidden, const SecureDeletionData& secure_deletion_data) { bool use_sdd = requiresSecureDeletion(format); size_t info_len = hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize(); if (use_sdd) { info_len += sizeof(kAesGcmDescriptor2) + secure_deletion_data.factory_reset_secret.SerializedSize() + secure_deletion_data.secure_deletion_secret.SerializedSize() + sizeof(secure_deletion_data.key_slot); } else { info_len += sizeof(kAesGcmDescriptor1); } Buffer info(info_len); info.write(use_sdd ? kAesGcmDescriptor2 : kAesGcmDescriptor1); uint8_t* buf = info.peek_write(); const uint8_t* end = info.peek_write() + info.available_write(); buf = hidden.Serialize(buf, end); buf = hw_enforced.Serialize(buf, end); buf = sw_enforced.Serialize(buf, end); if (use_sdd) { buf = secure_deletion_data.factory_reset_secret.Serialize(buf, end); buf = secure_deletion_data.secure_deletion_secret.Serialize(buf, end); static_assert(std::is_same_v); buf = append_uint32_to_buf(buf, end, secure_deletion_data.key_slot); } if (!buf || buf != end || !info.advance_write(buf - info.peek_write())) { LOG_S("Buffer management error", 0); return KM_ERROR_UNKNOWN_ERROR; } return info; } KmErrorOr DeriveAesGcmKeyEncryptionKey(const AuthEncryptedBlobFormat format, // const AuthorizationSet& hw_enforced, // const AuthorizationSet& sw_enforced, // const AuthorizationSet& hidden, // const SecureDeletionData& secure_deletion_data, // const KeymasterKeyBlob& master_key) { Buffer prk(EVP_MAX_MD_SIZE); size_t out_len = EVP_MAX_MD_SIZE; if (!HKDF_extract(prk.peek_write(), &out_len, EVP_sha256(), master_key.key_material, master_key.key_material_size, nullptr /* salt */, 0 /* salt_len */)) { return TranslateLastOpenSslError(); } KmErrorOr info = BuildDerivationInfo(format, hw_enforced, sw_enforced, hidden, secure_deletion_data); if (!info) return info.error(); if (!prk.advance_write(out_len) || !prk.available_read() || !info->available_read()) { return KM_ERROR_UNKNOWN_ERROR; } Buffer keyEncryptionKey(kAes256KeyLength); if (!HKDF_expand(keyEncryptionKey.peek_write(), keyEncryptionKey.available_write(), // EVP_sha256(), // prk.peek_read(), prk.available_read(), // info->peek_read(), info->available_read())) { return TranslateLastOpenSslError(); } return keyEncryptionKey; } KmErrorOr AesGcmEncryptKey(const AuthorizationSet& hw_enforced, // const AuthorizationSet& sw_enforced, // const AuthorizationSet& hidden, // const SecureDeletionData& secure_deletion_data, // const KeymasterKeyBlob& master_key, // const KeymasterKeyBlob& plaintext, // const AuthEncryptedBlobFormat format, // Buffer nonce) { KmErrorOr kek = DeriveAesGcmKeyEncryptionKey(format, hw_enforced, sw_enforced, hidden, secure_deletion_data, master_key); if (!kek) return kek.error(); bssl::UniquePtr ctx(EVP_CIPHER_CTX_new()); if (!ctx) return KM_ERROR_MEMORY_ALLOCATION_FAILED; int ciphertext_len = plaintext.size(); int unused_len = 0; EncryptedKey retval; retval.format = format; retval.ciphertext = KeymasterKeyBlob(ciphertext_len); retval.nonce = move(nonce); retval.tag = Buffer(kAesGcmTagLength); if (!(EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, kek->peek_read(), retval.nonce.peek_read()) && EVP_EncryptUpdate(ctx.get(), retval.ciphertext.writable_data(), &ciphertext_len, plaintext.key_material, plaintext.size()) && EVP_EncryptFinal_ex(ctx.get(), retval.ciphertext.writable_data() /* not written to */, &unused_len) && EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagLength, retval.tag.peek_write()))) { return TranslateLastOpenSslError(); } if (plaintext.size() != static_cast(ciphertext_len) || 0 != unused_len || !retval.tag.advance_write(kAesGcmTagLength)) { return KM_ERROR_UNKNOWN_ERROR; } return retval; } KmErrorOr AesGcmDecryptKey(const DeserializedKey& key, const AuthorizationSet& hidden, const SecureDeletionData& secure_deletion_data, const KeymasterKeyBlob& master_key) { KmErrorOr kek = DeriveAesGcmKeyEncryptionKey(key.encrypted_key.format, key.hw_enforced, key.sw_enforced, hidden, secure_deletion_data, master_key); if (!kek) return kek.error(); bssl::UniquePtr ctx(EVP_CIPHER_CTX_new()); if (!ctx) return KM_ERROR_MEMORY_ALLOCATION_FAILED; int plaintext_len = key.encrypted_key.ciphertext.size(); int unused_len = 0; KeymasterKeyBlob plaintext(plaintext_len); if (!(EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, kek->peek_read(), key.encrypted_key.nonce.peek_read()) && EVP_DecryptUpdate(ctx.get(), plaintext.writable_data(), &plaintext_len, key.encrypted_key.ciphertext.key_material, key.encrypted_key.ciphertext.size()) && EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagLength, const_cast(key.encrypted_key.tag.peek_read())))) { return TranslateLastOpenSslError(); } if (!EVP_DecryptFinal_ex(ctx.get(), plaintext.writable_data() /* not written to */, &unused_len)) { return KM_ERROR_INVALID_KEY_BLOB; } if (key.encrypted_key.ciphertext.size() != plaintext.size() || 0 != unused_len) { return KM_ERROR_UNKNOWN_ERROR; } return plaintext; } } // namespace KmErrorOr SerializeAuthEncryptedBlob(const EncryptedKey& encrypted_key, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced, uint32_t key_slot) { bool use_key_slot = requiresSecureDeletion(encrypted_key.format); size_t size = 1 /* version byte */ + encrypted_key.nonce.SerializedSize() + encrypted_key.ciphertext.SerializedSize() + encrypted_key.tag.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize(); if (use_key_slot) size += sizeof(key_slot); if (isVersionedFormat(encrypted_key.format)) { size += sizeof(encrypted_key.kdf_version); size += sizeof(encrypted_key.addl_info); } KeymasterKeyBlob retval; if (!retval.Reset(size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; uint8_t* buf = retval.writable_data(); const uint8_t* end = retval.end(); *buf++ = encrypted_key.format; buf = encrypted_key.nonce.Serialize(buf, end); buf = encrypted_key.ciphertext.Serialize(buf, end); buf = encrypted_key.tag.Serialize(buf, end); if (isVersionedFormat(encrypted_key.format)) { buf = append_uint32_to_buf(buf, end, encrypted_key.kdf_version); buf = append_uint32_to_buf(buf, end, encrypted_key.addl_info); } buf = hw_enforced.Serialize(buf, end); buf = sw_enforced.Serialize(buf, end); if (use_key_slot) buf = append_uint32_to_buf(buf, end, key_slot); if (buf != retval.end()) return KM_ERROR_UNKNOWN_ERROR; return retval; } KmErrorOr DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob) { if (!key_blob.key_material || key_blob.key_material_size == 0) return KM_ERROR_INVALID_KEY_BLOB; const uint8_t* tmp = key_blob.key_material; const uint8_t** buf_ptr = &tmp; const uint8_t* end = tmp + key_blob.key_material_size; if (end <= *buf_ptr) return KM_ERROR_INVALID_KEY_BLOB; DeserializedKey retval{}; retval.encrypted_key.format = static_cast(*(*buf_ptr)++); if (!retval.encrypted_key.nonce.Deserialize(buf_ptr, end) || // !retval.encrypted_key.ciphertext.Deserialize(buf_ptr, end) || // !retval.encrypted_key.tag.Deserialize(buf_ptr, end)) { return KM_ERROR_INVALID_KEY_BLOB; } if (isVersionedFormat(retval.encrypted_key.format)) { if (!copy_uint32_from_buf(buf_ptr, end, &retval.encrypted_key.kdf_version) || !copy_uint32_from_buf(buf_ptr, end, &retval.encrypted_key.addl_info)) { return KM_ERROR_INVALID_KEY_BLOB; } } if (!retval.hw_enforced.Deserialize(buf_ptr, end) || // !retval.sw_enforced.Deserialize(buf_ptr, end)) { return KM_ERROR_INVALID_KEY_BLOB; } if (requiresSecureDeletion(retval.encrypted_key.format)) { if (!copy_uint32_from_buf(buf_ptr, end, &retval.key_slot)) { return KM_ERROR_INVALID_KEY_BLOB; } } if (*buf_ptr != end) return KM_ERROR_INVALID_KEY_BLOB; switch (retval.encrypted_key.format) { case AES_OCB: if (retval.encrypted_key.nonce.available_read() != OCB_NONCE_LENGTH || retval.encrypted_key.tag.available_read() != OCB_TAG_LENGTH) { return KM_ERROR_INVALID_KEY_BLOB; } return retval; case AES_GCM_WITH_SW_ENFORCED: case AES_GCM_WITH_SECURE_DELETION: case AES_GCM_WITH_SW_ENFORCED_VERSIONED: case AES_GCM_WITH_SECURE_DELETION_VERSIONED: if (retval.encrypted_key.nonce.available_read() != kAesGcmNonceLength || retval.encrypted_key.tag.available_read() != kAesGcmTagLength) { return KM_ERROR_INVALID_KEY_BLOB; } return retval; } LOG_E("Invalid key blob format %d", retval.encrypted_key.format); return KM_ERROR_INVALID_KEY_BLOB; } KmErrorOr EncryptKey(const KeymasterKeyBlob& plaintext, AuthEncryptedBlobFormat format, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden, const SecureDeletionData& secure_deletion_data, const KeymasterKeyBlob& master_key, const RandomSource& random) { switch (format) { case AES_OCB: { EncryptedKey retval; retval.format = format; auto nonce = generate_nonce(random, OCB_NONCE_LENGTH); if (!nonce) return nonce.error(); retval.nonce = std::move(*nonce); retval.tag.Reinitialize(OCB_TAG_LENGTH); keymaster_error_t error = OcbEncryptKey(hw_enforced, sw_enforced, hidden, master_key, plaintext, retval.nonce, &retval.ciphertext, &retval.tag); if (error != KM_ERROR_OK) return error; return retval; } case AES_GCM_WITH_SW_ENFORCED: case AES_GCM_WITH_SECURE_DELETION: case AES_GCM_WITH_SW_ENFORCED_VERSIONED: case AES_GCM_WITH_SECURE_DELETION_VERSIONED: { auto nonce = generate_nonce(random, kAesGcmNonceLength); if (!nonce) return nonce.error(); return AesGcmEncryptKey(hw_enforced, sw_enforced, hidden, secure_deletion_data, master_key, plaintext, format, std::move(*nonce)); } } LOG_E("Invalid key blob format %d", format); return KM_ERROR_UNKNOWN_ERROR; } KmErrorOr DecryptKey(const DeserializedKey& key, const AuthorizationSet& hidden, const SecureDeletionData& secure_deletion_data, const KeymasterKeyBlob& master_key) { KeymasterKeyBlob retval; switch (key.encrypted_key.format) { case AES_OCB: { keymaster_error_t error = OcbDecryptKey( key.hw_enforced, key.sw_enforced, hidden, master_key, key.encrypted_key.ciphertext, key.encrypted_key.nonce, key.encrypted_key.tag, &retval); if (error != KM_ERROR_OK) return error; return retval; } case AES_GCM_WITH_SW_ENFORCED: case AES_GCM_WITH_SECURE_DELETION: case AES_GCM_WITH_SW_ENFORCED_VERSIONED: case AES_GCM_WITH_SECURE_DELETION_VERSIONED: return AesGcmDecryptKey(key, hidden, secure_deletion_data, master_key); } LOG_E("Invalid key blob format %d", key.encrypted_key.format); return KM_ERROR_INVALID_KEY_BLOB; } bool requiresSecureDeletion(const AuthEncryptedBlobFormat& fmt) { return fmt == AES_GCM_WITH_SECURE_DELETION || fmt == AES_GCM_WITH_SECURE_DELETION_VERSIONED; } bool isVersionedFormat(const AuthEncryptedBlobFormat& fmt) { return fmt == AES_GCM_WITH_SW_ENFORCED_VERSIONED || fmt == AES_GCM_WITH_SECURE_DELETION_VERSIONED; } } // namespace keymaster