Locksmith: Secure Android Keystore Based on VirtualizedTrusted Environments
Luís Miguel da Silveira Freitas Fernandes Tonicha
Thesis to obtain the Master of Science Degree in
Information Systems and Computer Engineering
Supervisor(s): Prof. Nuno Miguel Carvalho dos Santos
Examination Committee
Chairperson: Prof. Paolo RomanoSupervisor: Prof. Nuno Miguel Carvalho dos Santos
Member of the Committee: Prof. Bernardo Luís da Silva Ferreira
November 2020
ii
Acknowledgments
I would like to start by thanking my professor Nuno Santos, whose expertise and guidance was invalu-
able. Furthermore, his patience and support were essential to me, as I’ve never tackled a project of this
complexity before. I dealt with several hardships thanks to his knowledge and availability.
I want to also thank and congratulate David Cerdeira (and his team), of Universidade do Minho, for
his excellent work on the main technology we are focusing this project on. Thank you for the unending
hours you spent debugging and improving the integration of your project with ours, and I hope the rest
of your doctorate keeps going as well as it is now.
To my sister and parents, that once more offered me their unconditional support, and always had my
back for the best and for the worst.
And last but definitely not least, I thank my friend Francisco Canana for his support and camaraderie
throughout this Master’s degree.
iii
iv
Resumo
O Sistema Operativo e tecnologia Android representam uma grande fatia do mercado de dispositivos
moveis. Estes aparelhos sao utilizados para guardar e trabalhar com informacao pessoal e privada.
Para proteger esses dados, o Android utiliza uma tecnologia chamada ARM TrustZone – uma arquitec-
tura de hardware que isola funcionalidades crıticas do resto do Sistema Operativo. Essas funcionali-
dades sao executadas num ambiente protegido por software altamente privilegiado chamado Trusted
Execution Environment (TEE). No entanto, este software tem sido alvo de ataques complexos, levando
a perdas catastroficas como a exposicao e hijacking do sistema de ficheiros Android cifrado e protegido,
resultando na divulgacao de chaves aplicacionais e material altamente confidencial. De modo a evitar
a utilizacao de codigo especıfico a determinadas aplicacoes dentro do TEE, propomos o Locksmith –
uma arquitectura de seguranca para o modulo de seguranca Keymaster, que atraves de um hipervi-
sor leve, usa uma enclave de confianca onde operacoes de carater confidencial realizar-se-ao e onde
chaves/segredos serao armazenados. A nossa arquitectura demonstra que a migracao de algumas
operacoes crıticas outrora realizadas dentro da TEE podem ser migradas para enclaves suportados por
um hipervisor. Esta abordagem tem por efeito uma reducao da superfıcie de ataque da TEE e portanto
um incremento da seguranca do dispositivo movel.
Palavras-chave: Android, Seguranca, TEE, TrustZone, Keymaster, Enclave
v
vi
Abstract
The Android Operating System has been adopted by a large share of the mobile device market. An-
droid devices are widely used for storing and processing personal and privacy-sensitive information.
To protect such data, Android uses a technology called ARM TrustZone – a hardware architecture that
isolates critical operations from the rest of the Operating System. Such operations are executed inside
a protected environment which is maintained by highly privileged software named Trusted Execution
Environment (TEE). However, this kind of software has increasingly been the target of complex attacks,
leading to catastrophic losses such as exposure and hijacking of the encrypted and protected Android
file system, resulting in the disclosure of application keys and highly confidential data. To avoid using
specific code for certain applications within the TEE, we propose Locksmith – a security architecture
for the Keymaster security module, which, by leveraging a light hypervisor, creates a reliable enclave
where confidential operations will take place and where keys/secrets will be stored. Our architecture
demonstrates that the migration of some critical operations that were formerly performed inside the TEE
can be safely migrated into enclaves backed by a hypervisor. This approach brings about a reduction in
the attack surface of the TEE thereby increasing the overall security of Android mobile devices.
Keywords: Android, Security, TEE, TrustZone, Keymaster, Enclave
vii
viii
Contents
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
List of Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
List of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Nomenclature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Document Outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Background 5
2.1 ARM TrustZone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1 Android Security Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.2 Android Keystore Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3 Related Work 13
3.1 Communication Between Worlds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Simplifying Trust Inside the TrustZone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 Virtualizing ARM TrustZone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.4 Integrating TrustZone With a Mobile Operating System . . . . . . . . . . . . . . . . . . . . 16
3.5 Software Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.6 User-space Enclaves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.7 Kernel-level protection for ARM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4 Architecture 23
4.1 Motivational Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2 Threat Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3 Locksmith Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
ix
4.3.1 Locker: Intercepting Keymaster Calls . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.3.2 Bao: Containing Code and Data inside Enclaves . . . . . . . . . . . . . . . . . . . 27
4.3.3 Lockpick: Guaranteeing Functionality inside a Minimal Environment . . . . . . . . 27
4.4 Initial System Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.5 System Bootstrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.6 Lockpick API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.7 Communication between Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.8 Storage and Persistence of Key Material . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5 Implementation 35
5.1 Initial Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.1.1 Emulating Enclaves via QEMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.1.2 Communication between Software Keymaster and the Emulated Enclave . . . . . 36
5.1.3 Modifying Android Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.2 Locker Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.2.1 Choosing a Design Pattern for the Locker Code . . . . . . . . . . . . . . . . . . . . 39
5.2.2 Handling Keymaster API Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3 Lockpick Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3.1 Implementing Lockpick as a Rust Library . . . . . . . . . . . . . . . . . . . . . . . 41
5.3.2 Lightweight C Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.4 Locksmith Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.4.1 Deploying Locker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.4.2 Preparing Lockpick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.5 Issues with Bao Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6 Evaluation 47
6.1 Evaluation Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.2 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.2.1 Global Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.2.2 Micro Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
6.3 TCB Size and Memory Footprint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
6.4 Security Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.4.1 Effective Security Guarantees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.4.2 Non mitigated attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7 Conclusions 55
7.1 Achievements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Bibliography 59
x
List of Tables
2.1 Keymaster functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.1 Lockpick API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.1 System’s global benchmark. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.2 RTT/Communication establishment benchmark. . . . . . . . . . . . . . . . . . . . . . . . . 51
6.3 Locksmith codebase statistics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
xi
xii
List of Figures
2.1 Cortex-A TrustZone. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Architecture of the Android Keystore service. . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.1 SeCReT design overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2 Pearl-TEE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.3 vTZ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.4 PrivateZone architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.5 Samsung’s KNOX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.6 Sanctuary overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.7 SKEE’s design. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.1 Secure authentication and communication between a user and an online banking service. 24
4.2 Man-in-the-middle attack via certificate forgery. . . . . . . . . . . . . . . . . . . . . . . . . 24
4.3 Locksmith architecture: its specific components are highlighted in yellow. . . . . . . . . . 25
4.4 Initial Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.5 Possible Keymaster devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.6 Bao’s communication architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.7 Storage solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.1 Android running Debian via QEMU. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2 Initial protocol’s main loop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.3 First prototype’s structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.4 Locker singleton object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.5 liblockworker’s basic state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.6 The import function and unsafe tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.7 Lockpick’s build process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.8 ROCK960 development board. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.1 Keystore testing Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.2 Simple speed measurement. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
6.3 Micro/API benchmarks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
xiii
xiv
Chapter 1
Introduction
Personal mobile devices are becoming increasingly more ubiquitous and as such, users are trusting
these devices with sensitive and confidential data due to its convenience and portability. They are seen
as everyday utilities, and users might not even realize the amount and quality of the information they
store and access on their personal devices.
Simultaneously, defensive measures need to keep evolving – as users get exposed to more complex
threats, they don’t necessarily become more aware of them. Studies [1] show that users in general
have a lax policy regarding security measures, and are more worried with malware from applications
they install than targeted information theft. For example, Mylonas et al. [2] report that official application
repositories are trusted blindly and most security messages on permission oriented systems such as
Android are disregarded. This also happens with more “obvious” security measures such as locking
mechanisms – many users still underestimate the extent and nature of the data they are storing and
choose to not use any authentication system [3]. Alsaleh et al. [4] also confirm that the usefulness and
convenience of applications affect users’ decision to act in a safe manner. Mobile technology keeps
evolving and user awareness needs to be constantly growing in order to avoid problems as these.
However, user awareness alone is not enough. The Google Android team stays pushing for stronger
security on each Android release, but “pure” Android phones are a small minority, and vendors tend to
keep their implementations behind a proprietary wall, often not disclosing major flaws until it’s too late.
All of these factors motivate the need to develop a more robust security system, since there is a limit
on the effort that is educating users of good security practices. This thesis aims at contributing to the
enhancement of the security mechanisms of modern Android platforms.
1.1 Motivation
Currently, Android is the most widely-deployed, user-centered operating system (OS) [5] for mobile
devices. It provides a common interface for global users to interact with digital services, across a range
of different form factors. Android is designed to achieve a mix of security and usability, while addressing
a host of practical threats in various scenarios and being useful to regular, non-tech-savvy users.
1
From the security perspective, ARM TrustZone technology plays a fundamental role in the Android
OS. Today, this mobile operating system depends on a Trusted Computing Base (TCB) which starts with
the boot loader (which in itself represents multiple stages), and includes the Linux kernel and other priv-
ileged components of the Android framework, including hardware drivers and userspace components.
The TCB also includes software components allocated inside a Trusted Execution Environment (TEE)
provided by ARM TrustZone technology. The TEE aims to provide defense mechanisms against a poten-
tial security breach in the Android OS kernel. In particular, Android uses a mobile phone’s TEE to host
isolated security modules such as the Keymaster and Strongbox. Keymaster, for instance, is a Keystore
implementation that runs inside a TEE, typically inside ARM TrustZone’s security world, which protects
cryptographic keys and confidential data, meaning that even an attacker that compromises the kernel of
the Android OS cannot access this sensitive material.
However, despite the security benefits of TrustZone-assisted TEEs, there are also risks involved.
Even though this technology has been around for more than a decade now, only in the recent years
have TrustZone-based TEEs seen an increase in overall interest, mostly due to its low exposure to the
world outside vendor development. Software development for TEE has been largely kept “private” by
vendors, and it essentially consists in the implementation of applications named Trusted Application (TA).
TAs run inside the TEE, and have typically to deal with security-sensitive data: some TAs implement OS-
level logic, such as Android’s Keymaster; others implement user-level logic, e.g., mobile payments, DRM
protection. Unfortunately, recent studies [6] show that TAs often contain critical security vulnerabilities
which can lead malicious actors to exploit and perform privilege escalation attacks, extract confidential
data or even compromise the entire system, due to the privileged nature of this ecosystem. Moreover,
TAs are also growing in number, thereby increasing the TCB size and the attack surface.
1.2 Objectives
The goal of this work is to reduce the attack surface of current TrustZone-aware TEEs by displacing TA-
specific logic from the highly-privileged secure world into less-privileged sandboxes instantiated in the
normal world. This approach would reduce the attack surface of a potential adversary by restricting the
opportunity to exploit a vulnerability inside the TEE and escalate privileges to control the whole Android
OS. To demonstrate the benefits of this approach, we propose to implement a secure Keymaster for
Android that does not require to run a Trusted Application code inside TEE, and yet offers similar or
even stronger security guarantees for end-users. By showing that this engineering can be performed for
such a critical OS module as the Android’s Keymaster, we demonstrate that this architecture is general
and that it can be applied for arbitrary user-level TAs.
Concretely, we aim to design, implement, and evaluate Locksmith, a security architecture for Android
devices, which doesn’t use any TEE or Trusted Applications, and instead executes Keymaster inside
a protected environment – an enclave, created by a lightweight hypervisor. This way it runs entirely
separated of the rest of the system, with its own CPU core and memory region. With this we are trying
to ensure that there is no way of tampering sensitive/private material typically stored in a TEE, even if
2
the rest of the machine is compromised.
Furthermore, to reduce the chance of vulnerabilities in the code responsible for performing encryption
and key management operations, we aim to implement it in Rust [7], a modern systems programming
language with security as one of its pillars, featuring capabilities like memory safety and automatic bound
checking, leading to much fewer developer mistakes and increased performance.
1.2.1 Contributions
This work focuses on improving the current Keymaster system and overall Android security architecture
by building Locksmith. Specifically, we produce the following contributions:
• Improvement of the integrity, confidentiality, and privacy of data on Android devices by developing
a new Keymaster security component, using a modern and safer programming language;
• Detachment of Android key management/storage from TEE;
• Isolation of the developed components and the rest of the device;
• No significant performance overhead over the existing solutions;
• A thorough experimental evaluation simulating real workloads and different environments
1.3 Document Outline
This thesis is structured in the following manner. Chapters 2 and 3 lay the foundations for our project,
providing theoretical and practical background and showcasing relevant work done in this field, where
the Android Operating System is dissected from a security point-of-view. Chapter 4 presents the pro-
posed architecture of Locksmith, and the following Chapter 5 the steps needed to implement it and the
reasoning behind our choices. Finally, Chapter 6 presents our experimental evaluation of the whole
system and Chapter 7 concludes this report and presents ideas to enhance Locksmith in the future.
3
4
Chapter 2
Background
This section provides some necessary background information in order to understand our work. It spans
several technological domains from low level hardware technology like the TrustZone to the Android
Operating System, whose security principles must be understood to justify our architectural choices.
We finish this chapter by introducing the key component in Android security, the Keystore.
2.1 ARM TrustZone
ARM is one of the most licensed and used microcontrollers in the world. These processors are used in
a range of settings and devices, from mobile phones to medical devices and other embedded systems.
Their low power usage and reasonable performance make them an attractive architecture for mobile
devices, since these are two main factors that users search for.
There have been several generations of ARM cores, and the most recent one is the Cortex series,
comprised of the Cortex-A, Cortex-M and Cortex-R microarchitectures. The first one is specially im-
portant since it is an application processor designed to run fully fledged Operating Systems, supporting
both 32 bit (ARMv7) and 64 bit (ARMv8) applications. The less powerful Cortex-M is sometimes used
to complement another processor, for example on a System-on-Chip dedicated to cryptographic opera-
tions [8].
The sensitive and private data of personal devices has made them attractive targets for malicious
actors, which has led to the development of security measures on all layers of these devices. Well
developed applications and a robust OS are not enough if the base of the “trust chain” is compromised.
In order to harden these devices, ARM developers sought to develop a hardware technology, de-
ployed first in 2004 on ARM Cortex-A processors [9]. It is a system-wide approach at the hardware level
that uses the concept of a normal and secure worlds, shown in Figure 2.1. This means that any software
running on a processor with TrustZone is either on a normal/non-secure state or in a secure state.
The secure world is a “mirrored” version of the normal world, which means it also has applications
running on an operating system (normally a much smaller sized one). It hosts a Trusted Execution
Environment, which will later be explored.
5
Secure Monitor
Non-Secure (Rich)OS
Non-SecureApplications
NormalWorld
SecureWorld
Secure OS
Secure Applications
Figure 2.1: Cortex-A TrustZone.
Context switching between the two worlds is provided on demand by a Secure Monitor, running
typically on EL3. A Secure Monitor Call instruction is issued every time a component on the normal
world needs to perform security-sensitive operations, switching to the secure world, which is also used
to switch back.
TrustZone technology and its security extensions facilitates the development of security applications
on the ARM architecture, and so it has seen a plethora of several use cases. Software frameworks like
TrustFrame [10] and even a full .NET mobile runtime [11] were developed for safer and faster TrustZone
development. Regarding software isolation, several tools like ARMlock [12], NaCL [13] and ARMor [14]
make use of the TrustZone’s sandboxing capabilities to protect a running Real Time Operating System
and its critical loops while keeping control-flow and and memory integrity.
Regarding virtualization, Sandro et al. [15] worked on the possibility of the TrustZone providing a
hardware-based form of system isolation and proposed an architecture consisting of a Virtual Machine
for each one of the world states, controlled by a hypervisor working above the Secure Monitor. This ar-
chitecture, with some modifications, is in part what Android devices use nowadays – a Trusted Execution
Environment supervised by a hypervisor above the hardware.
2.1.1 Android Security Model
So far we have explored security measures deployed at the hardware level. Hardware is the start of the
trust chain, however security measures need to reach all layers and components of the device. In the
following section we will explore Android’s security architecture and some of its most important features,
which need to be understood in order to maintain and improve upon them.
6
Android ecosystem:
Android developers recognize the need for a mutual growth between all parties involved with the sys-
tem [5]. This means that their platform must have an environment that is safe by default, and the
meaningful parties (end users, developers and the OS) can have beneficial terms of engagement. If
by any reason these parties cannot reach an agreement on a certain action, then the security model is
designed to prohibit said action (default-deny).
Since Android is an operating system focused on the end user, it aims for simplicity while being
remaining attractive to developers. Being the user the primary target, Android’s interfaces and user
experience need to be secure by default and ask for explicit consent for actions that may be a threat to
the user’s privacy or security. Non-expert users should not have to deal with technical security questions
since they may not be able to answer in a safe way.
Due to the immense adoption of Android devices, which encompasses hundreds of different OEMs
and OMDs, devices using Android as a trademarked name need to pass a Compatibility Test Suite so
developers can deploy to a multitude of different devices. Applications can also be developed in any
language, as long as they have a Java wrapper which can bootstrap and interact with the OS. This
allows for greater flexibility when designing applications while keeping safety and boundary checks in
runtime.
Android security principles:
There are major principles on which Android’s security model is based on. First, agents control access
to data that they create. This means that any agent that creates a data item has implicit control over it.
Second, consent is informed and explicit. Consent decisions should be based on information about the
action about to be taken and must have meaningful ways of being granted or denied.
Another principle is that by design, any component should respect security and privacy assumptions,
even if it means blocking potentially harmful use cases. This serves as an incentive for developers and
device manufacturers to refine and work on new interfaces deemed more secure.
Finally, Android aims to achieve defense in depth – its approach on security makes it that even if a
security assumption fails or has any bugs, it will not compromise the rest of the system. This is specially
important due to the huge variety of environments that Android runs on and the different approaches
that application developers and device vendors can take on.
Authentication:
The main authentication method on mobile devices is the lockscreen. Lockscreens on other mobile
devices nowadays use mostly a binary model: either the device is fully accessible or most functions,
especially privacy sensitive ones like telephony, are disabled. Since end users want fast interactions with
their mobile phones and not be hindered by long passwords, but still need some for of authentication
(swipe-only lockscreens are not safe at all), a balance between usability and safety is essential.
7
Android achieves this with tiered authentication: a knowledge-factor based authentication system
that can be used with convenient mechanisms constrained by the level of security they offer. A pri-
mary authentication provides access to all functions of the device, which by default include PIN, pattern
and password methods. Secondary authentication are biometrics considered strong enough that they
unlock most features yet critical operations, like file-based or full-disk decryption aren’t still accessible.
Finally, tertiary authentication is left for “weak” biometrics or alternative unlocking methods, e.g., use a
bluetooth-paired device.
Isolation:
One of the most used security techniques used by the Android infrastructure is sandboxing, which occurs
not just in applications [16] but in other layers of the system. The original Discretionary Access Control
(DAC) [17] sandbox created a barrier between apps and the system by providing each one with an
unique UNIX user ID and a directory owned exclusively by that user.
This approach comes with a number of disadvantages, such as processes that ran as root were
not isolated at all and could manipulate apps, the system and confidential data. However on recent
Android releases, following applications, system processes get sandboxed too, which limits a set of
UID sandboxes for several system processes. Other important processes such as WiFi, Bluetooth and
telephony have UID isolation too.
Below the application layer which gets increasingly more secure, the kernel starts becoming an
alluring target for privilege escalation attacks [18]. With this in mind, Android uses technologies like
TEEs and the TrustZone to mitigate attacks on the kernel.
Data encryption:
Data encryption is needed in order to enforce the security model, especially the “all actors consent”
tenet. Android has had Full Disk Encryption (FDE) since version 5.0, which is a mechanism that through
a credential protected key encrypted the entire user data partition. One of the main disadvantages of
this method is that some important parts of the device, like the emergency dialer, remained inaccessible
until the user unlocked it.
Android 7.0 introduces File Based Encryption (FBE), which allows encryption of specific files for
multiple users, effectively protecting data on a per-user basis. In contrast to FDE, devices with FBE can
get their keys derived from a TEE or similar environment, which strengthens the system a lot by mixing
hardware-bound cryptography (inaccessible to the kernel and above) and user knowledge. Direct Boot,
which comes with FBE, removes the restriction on using basic functions with a locked screen. Regarding
encryption at the network level, Android provides and promotes the use of TLS options, since link level
encryption is insufficient.
8
Figure 2.2: Architecture of the Android Keystore service.
System integrity:
Android supports Verified Boot and the dm-verity kernel feature since version 4.4. This ensures that all
executed code comes from a trusted source, establishing a full chain of trust, starting from the hardware
and its lower level components, to important partitions like system and vendor. During boot, each stage
verifies and authenticates the next stage before proceeding.
Verified Boot also employs rollback protection, which checks if the correct version of the OS is run-
ning, ensuring devices only update to a newer version and can be used to inform the user of the integrity
of the system. Furthermore, starting on Android 7.0, compromised devices aren’t allowed to boot and
forward error correction has been deployed to tackle non-malicious data corruption.
2.1.2 Android Keystore Service
From the application point of view, Keystore is the library responsible for storing private keys in a con-
tainer, protecting key material from unauthorized use. However this is just the high level interface ex-
posed to clients, since Keymaster (Figure 2.2), is the underlying component that performs these ser-
vices.
The current ecosystem, Figure 2.2, can be split in two worlds: the normal world, also known as
legacy world, where the Android stack and Linux Kernel resides, and a secure world, which runs inside
a TEE. Hardware wise, the TEE is normally implemented based on ARM TrustZone technology.
The normal world contains the Android operating system and all its components, such as user ap-
9
plications and system services. We’re interested specifically in the Keymaster, which performs security
services such as accessing and storing confidential data.
Keymaster is divided into several parts, starting with Keystore, which is the Java library that user
applications interact with. After an API call is performed from an application, the Keymaster Hardware
Abstraction Layer (HAL) – which is an OEM-provided, dynamically loadable library – marshals this re-
quest, with semantics defined in a generic HIDL (HAL language), to a specific kernel driver.
This driver works as a secure channel between the normal and secure world. The Keymaster allows
custom implementations of the underlying API via the HAL. The functions that a working Keymaster
(version 3) should support, along with a brief explanation, are represented in Table 2.1. Normally, as
explained next, Android provides two underlying Keymaster implementation: a hardware-backed one
that resides in the TEE, and a local implementation inside the Android OS.
Hardware-backed Keymaster:
Before Android 6.0, Keystore already supported digital signing and verification operations, and the gen-
eration and import of asymmetric key pairs. With this version came support for symmetric cryptographic
primitives (AES and HMAC) and an access control for hardware-backed keys.
Devices with TEEs (the majority nowadays) such as the one provided by TrustZone can use the
Hardware Abstraction Layer to communicate with the normal world and vice-versa, so confidential ma-
terial like encrypted blobs and keys never leave the secure world, which are handled by Keymaster’s TA,
as shown in Figure 2.2. No security sensitive operations happen outside the TEE.
API Function DescriptiongetHardwareFeatures Returns characteristics about the underlying secure hardwareaddRngEntropy Adds caller-provided entropy to the pool for generating random numbersgenerateKey Generates a new cryptographic keygetKeyCharacteristics Returns parameters and authorizations associated with the provided keyimportKey Imports key material into Keymaster hardwareexportKey Exports a public key from a Keymaster RSA or EC key pairdeleteKey Deletes the provided keydeleteAllKeys Deletes all keysdestroyAttestationIds Permanently disable the ID attestation featurebegin Begins a cryptographic operationupdate Provides data to process in an ongoing operation started with “begin”finish Finishes an ongoing operation started with “begin”abort Aborts the in-progress operationget supported * Returns the list of algorithms/modes/formats supported
Table 2.1: Keymaster functions.
Softkeymaster:
Before hardware-backed cryptography became common in mobile devices, the original Keystore imple-
mentation worked as a single daemon which managed key blobs and encryption in a single binary. With
10
Android 4.1 came the HAL [19], a global interface that allowed third party vendors to interact with their
own Keymaster implementations through a standardised format.
In order for the HAL to work on devices with no hardware-backed implementations, a softkeymaster
software module performs all key operations using the OpenSSL library and without any hardware de-
pendencies. To the best of our knowledge, this module is present up until Android 8.1, and no longer
present after.
Summary
In this chapter we presented the main concepts and technologies that serve as a theoretical background
needed to understand our work. We deconstructed the Android Security Model and its tenets, after
which we provided insight on the current embedded systems state-of-the-art technology, the TrustZone,
finishing with a brief explanation on the Keystore/Keymaster symbiosis. In the next chapter we present
alternative solutions to some of the flaws our project is targeting.
11
12
Chapter 3
Related Work
A Trusted Execution Environment, or TEE, is a special, integrity-protected environment with common
capabilities such as processing, memory and storage [20]. Even though these solutions do not directly
affect the internal workings of the Android security model, all of them can be adapted for deployment on
mobile devices running modern hardware and the Android OS.
In this chapter, we will explore the impact and flaws of the TrustZone/TEE architecture and some
proposed solutions in related work, alongside a comparison with our own work.
3.1 Communication Between Worlds
Communication between the REE (the “Rich” Execution Environment) and TEE is not supervised by
TrustZone. The current architecture does not authenticate the access to its resources, so a process in
the REE that wants to use them needs to ask another process to open a channel of communication.
This special process then synchronously invokes a specific instruction with the arguments written on
domain-shared memory leading to a channel between the requesting process and the TrustZone getting
opened. However, an attacker with kernel privilege in the REE can still create a process that crafts
malicious requests to that channel in order to access TrustZone resources.
Jang et al. propose SeCReT [21], which works by creating a session key to sign the messages sent
during inter-domain (REE and TrustZone) communication. This session key is symmetrically assigned
for both the REE and TrustZone. It verifies every access to the memory page that contains the session
key, ensuring only predefined and legitimate user processes can read it, as seen in Figure 3.1.Every
time the processor mode switches to kernel, the session key memory page gets flushed and shadows
the register values, in order to prevent an attacker from reading it directly. Additionally, registers that
contain critical values like return addresses are verified by the framework.
Keymaster relies on communication with its TA counterpart for most of it services, since the con-
fidential data and services reside in the TEE. SeCReT presents an additional layer of security while
communicating with the TrustZone, which makes sure its resources are only accessed by authorized
users. This strengthens TrustZone usage but still relies on it heavily and our solution aims to reduce
13
dependency on the TEE. By having Keymaster working solely on the “pseudo” normal world that our
hypervisor will provide, no special measures like SeCReT will be needed.
Figure 3.1: SeCReT design overview.
3.2 Simplifying Trust Inside the TrustZone
Even though its present in most recent smartphones, neither Android nor iOS expose a public API that
enables application code to access the TrustZone. Many commercially deployed TEE OSes do not allow
any third party applications, or have a development and deployment process so complicated that it does
not provide any incentives for developers wanting to work with them.
Also, unlike third-party applications that can freely be installed in an Android device, TAs need mutual
trust between all of them, so third-party applications can’t be installed at all. This is partly due to vendors
fearing that their TEE OS will not stand against intentional attacks from applications, so small size and
simplicity is preferred to maintain the high-assurance level of the TEE OS.
Huang et al. [22] developed Pearl-TEE, Figure 3.2, which removes the need for applications to mu-
tually trust each other. It defines an abstract TEE application model, which encompasses the types of
applications that can benefit from TrustZone’s security guarantees. Four types of applications are de-
fined: key storage; integrity and confidentiality; secure communication with a server and with a user. For
app isolation, Pearl-TEE runs on EL1 while the apps run on EL0. To prevent denial-of-service attacks, it
implements batch scheduling, which in absence of user interaction, each application gets a fixed amount
of time to run before another app takes it place.
Additionally, it also provides a storage implementation that’s optimized for storing keys (which is
mainly what Trusted Applications need to store) – each app gets an application-specific key that depends
on the Pearl-TEE master key (only accessible to the OS via secure boot), generated by encrypting the
14
Pearl-TEE OS
TEE Applications
Secure Element
Pearl-TEE Master Key
OS
User Applications
File system
Public Key of TrustedApplications
Network Stack
Pearl-TEENormalWorld
ARM & Secure Input
Application Servers
Private Key ofTrusted
Applications
Syscall Bridge
Figure 3.2: Pearl-TEE.
hash of the app itself with the master key. This way it reveals nothing about the master key while being
unique for each application. The OS can then use that application key to cipher and sign data that needs
to be stored in the normal world OS.
The authors report a TCB increase of just 3% and a processing overhead of under 20%. With this
model, Keymaster’s services could be broken down in to several Trusted Applications, depending on the
services that were being fragmented. This however, would just increase the dependency on the TEE
OS and its underlying limitations. For example, communication from the normal to the secure world isn’t
hardened, and an attacker could target and snoop this channel in order to find secrets.
3.3 Virtualizing ARM TrustZone
Typically, mobile phones have a device dependent, vendor deployed TEE-kernel, inaccessible in any
way after deployment. Even though there are open implementations, vendors like Samsung, Apple and
Huawei use their own TEE kernel, leading to exploits avoidable with proper collaboration [23–26]. No
third party TEE kernels can be installed (even after iOS jailbreak or Android root), leaving end-users
open to these attacks until they are patched. Since each TEE has a specific rootkey, and this key
authenticates all Trusted Applications, a new Trusted Application needs to be signed by the root key in
order to run on that specific device’s TEE. Furthermore, the TrustZone is designed to run exactly one
TEE, provided by hardware, which makes it impossible to run TEEs with different purposes.
Hua et al. [27] aim to safely provide virtualization of TrustZone while maintaining strong isolation
between guest TEEs. The proposed idea is splitting functionality from security by keeping one secure,
co-running VM to serve as a guest TEE, while utilizing the TrustZone to enforce isolation among the
guest TEEs and the running, untrusted hypervisor, as seen in Figure 3.3. They leverage a tiny monitor
inside the physical TrustZone that virtualizes and interposes world switching and memory mappings.
This way, more than one TEE is allowed to run on the device, with an acceptable overhead and strong
15
Non TEE Virtual Machine
Hypervisor
OS
User Applications
NormalWorld
SecureWorld
TEE Virtual Machine
Trusted OS
TrustedApplications
IsolatedEnvironment
Secured Modules(TCB)
Figure 3.3: vTZ.
isolation.
vTZ further leverages a few pieces of protected, self-contained code running in a Constrained Iso-
lated Execution Environment (CIEE) to provide secure virtualization and isolation among multiple guest
TEEs.
To enforce the booting integrity, the authors use the secure world to check the booting sequence,
as well as to perform integrity checking. Furthermore, vTZ uses Secured Memory Mapping, a module
in the secure world, to control all the stage-2 translation tables as well as hypervisor’s translation table,
providing efficient memory protection.
While leveraging several TEEs increase the user freedom and effectively stops malicious virtualized
TEEs from reaching other environments, it still poses all the disadvantages of relying solely on the
TrustZone: vendors can still deploy bug ridden TEEs, and inside them the Keymaster TA can still be
targeted.
3.4 Integrating TrustZone With a Mobile Operating System
Android applications leverage the TEE either by trusted applications being directly developed by the
vendor or developers have access to vendor’s SDK. Both of these solutions are a hindrance to TrustZone
adoption and development, since they are limited to the vendor’s interests (which are mainly commercial)
and most of the time they are behind a heavy paywall (access to vendor SDKs can cost thousands).
Aggravating this is the fact that TrustZone is locked down in commercial phones before shipment so no
code changes can happen in the actual end-user product.
Ying et al. [28] propose TruZ-Droid. It enables TrustZone support at the OS level, letting apps reuse
existing Android components for a smooth integration with TrustZone. To do this, two modules were
developed. At the user input level, TruZ-UI provides cross-OS binding support between secure world
UI interaction and normal world app code. A Keyboard Input trusted application gets the user input
16
OS PrEE KernelComponents Trusted OS
Normal World
User Applications PrivateZone-awareApplications
PrEE
SecurityCriticalLogic
TEE
TEEServicesControl Flow
PrivateZoneFramework
Monitor Switch
UserMode
KernelMode
MonitorMode
Software-basedIsolation
Hardware-basedIsolation
Figure 3.4: PrivateZone architecture.
via the trusted world which it then stores. In order for user apps to use this sensitive data, TruZ-HTTP
establishes a secure HTTPS connection between the app and its destination server, performing the SSL
protocol in the secure world too.
TruZ-Droid aims for a seamless integration of the TrustZone by allowing developers to access its
functionalities without any app logic inside the secure world. While this simplifies application develop-
ment, security-sensitive operations, like user input from the keyboard, it still relies heavily on the TEE
and specific trusted applications.
Jang et al. solution [29] creates an exclusive zone (PrEE) between the Rich OS (REE) and Secure
OS (TEE). PrivateZone allows for developers to protect and execute specific code inside this privileged
area. It utilizes ARM virtualization extensions so that during secure boot, two stage-2 page tables are
created for the PrEE and REE, thereby providing context switching between the three logical environ-
ments, represented in Figure 3.4. The TEE is physically isolated from the PrEE and REE, thanks to a
hardware-based access-control mechanism. A PrivateZone Library provides developers several opera-
tions that can be utilized to build PrivateZone-aware applications.
This approach is a radical one, since it essentially replaces the TrustZone by an architecture some-
what similar but more friendly to application developers. However, like stated, part of the TEE is still
used and now it needs manual validation by vendors before framework deployment. Additionally, be-
cause the current PrivateZone prototype does not support multi-threaded applications, this would hinder
most of Keymaster’s cryptographic operations. Overall, PrivateZone represents an increase in the TCB
that Locksmith won’t have since it operate in a trusted enclave.
3.5 Software Containers
Over the past years, there has been a growing trend among enterprises of “Bring Your Own Device”,
which means workers being encouraged to use their personal phones to work – running enterprise
17
software on their own machines. This keeps employees satisfied and productive, now that they can work
from anywhere. However, this also means having to deal with security policy enforcement, lost/stolen
devices with sensitive information and common threats like unsafe networks and malware.
Samsung’s KNOX [30] deploys a secure environment alongside the user’s environment, much like
a TEE. Depicted in Figure 3.5, it is a multi layer architecture that deploys several technologies, each
one secured by its predecessor. SEAndroid makes use of SELinux to enforce a fine-grained security
policy. TIMA, makes use of TrustZone’s feature to mainly perform periodic validations on the kernel code
and data (PKM) and the main element, Real-time Kernel Protection, which does several tasks, mainly
protecting memory pages from normal world reads all while logging everything, and setting the “warranty
bit” in case of device compromise.
Samsung’s solution is a fully fledged security model, with major changes to Android’s original security
platform. It makes no changes to the Keymaster system, but it’s used for security sensitive data, whose
applications run alongside the user environment.
This creates a constant security threat, because the container needs to check data from the within
too and not just from outside. The fact that it depends on a strong chain of trust between components,
starting on SEAndroid, exposes it to a bigger attack vector, like shown in early exploits [31–33].
There is another problem surrounding this solution, which is the authentication process. It requires
both a password and a PIN to launch secured apps and access files in a Knox container. In case the
user forgets this password, the user is prompted to enter an assigned PIN in order to get a hint for
the password. This hint generates the first and last character of the forgotten password, as well as the
total number of characters. This leads to a much smaller search space which could be guessed by a
malicious actor.
Furthermore, this PIN is stored in a plaintext format, inside Knox’s support application, which could
also be targeted and easily obtained.
Overall, this system is quite complex and ambitious, targeting every layer of the Android Operating
System, which in the end amounts to a big Trusted Computing Base, unlike our proposed solution.
Figure 3.5: Samsung’s KNOX.
18
3.6 User-space Enclaves
Another way to tackle the constrained use of TEEs and avoid strict deployment policies imposed by
device vendors is the creation of user-space enclaves. Brasser et al. propose Sanctuary, a novel system
architecture that allows unconstrained use of TEES in the TrustZone, without relying on virtualization
[34].
Sanctuary inherently de-privileges TrustZone enabled apps by moving them away from the secure
world to a special, isolated normal world division, thereby reducing the code based exposed in the
secure world. The authors call these special, security sensitive applications, “Sanctuary Apps” (or SA
for short), similar to Intel SGX’s user-space enclaves, represented in Figure 3.6.
These applications are isolated by partitioning and re-allocating system resources dynamically. Pro-
cessor cores and physical memory are temporarily exclusive for the isolated compartments to execute
SAs without halting the rest of the system. Particularly, they leverage the TrustZone’s Address-Space-
Controller (TZASC) to guarantee a hardware-enforced, two-way isolation between Sanctuary Applica-
tions and all the other system components.
The initial content of an SA gets loaded from normal, unprotected memory – therefore it can be
manipulated and should not contain any sensitive data. In order to counter this, Sanctuary provides
a mechanism to ensure the integrity and authenticity of an SA. This is achieved by a set of Trusted
Applications, providing security services, running in the secure world OS.
The first TA provides remote attestation. Through the TZ’s platform identity feature, an authentic
report of the system’s integrity can be delivered to a third party, creating a secure and authenticated
channel where critical data can be sent.
The second security service is Sealing, which allows SAs to store sensitive data in a way that just
instances of the provided SA can access that data. The system provides each SA an encryption key
unique to it by hashing its contents, a mechanism typically used for this kind of operation.
Overall, this system is a less intrusive approach compared to the previous one, and shares a lot
of similarities with our chosen hypervisor. However, it still focuses on the use of TEEs, choosing to
“containerize” its contents.
Figure 3.6: Sanctuary overview.
19
3.7 Kernel-level protection for ARM
To conclude this study on methods to harden ARM systems employing TrustZone technology without de-
pending on Trusted Execution Environments, we examine a novel way of strengthening kernel protection
and monitoring.
Ahmed et al. developed SKEE, a system that provides an isolated lightweight execution environment
at the privilege level of the kernel [35]. It does this by preventing the kernel from managing its own
memory translation tables, which separates isolated environments and the kernel since they typically
operate on the same level.
SKEE (represented in Figure 3.7) uses a two phase solution in order to achieve the requires isolation.
First, it creates a separate protected virtual address space just for itself. The memory layout of the entire
system is modified in a way that the memory regions used by the kernel overlap with SKEE. It achieves
this by changing the memory translation tables in a way that the kernel’s translation entries point to its
physical memory regions instead.
The second phase is depriving the kernel from the control of certain MMU functions, so the CPU
doesn’t get directed to memory translation tables other than what SKEE uses. This is done by instru-
menting the kernel code: removing these instruction if they change the location of memory translation
tables. A constant monitoring of the memory layout is also performed to guarantee that no other unveri-
fied privileged code is allowed to execute.
The isolation is kept throughout the system by forcing the kernel to go through a designated switch
gate, jumping to the isolated environment. This gate, also represented in Figure 3.7, was designed to
enforce a strict execution flow, both atomic and deterministic.
This novel system has a scope much smaller than our system, focusing on providing hard isolation
between a kernel and other isolated systems, such as TEEs. As is, it would only stop threats at a kernel
level, leaving the rest of the OS and the secure world a target for malicious actors.
Figure 3.7: SKEE’s design.
20
Summary
In this chapter we analysed several projects and their proposed solutions to some flaws with the current
TEE/Android architecture. We took a look at simpler proposals like secure channels between both worlds
and more complex, system wide solutions like Samsung’s multi layered KNOX. The following chapter we
reveal our solution and detail its proposed architecture.
21
22
Chapter 4
Architecture
The following chapter presents Locksmith and all its components, our proposed system for a reliable and
safe Keymaster, less exposed to the risks of current TEE implementations. We start with a motivational
example in order to provide a use case and establish a threat model, after which we explore in depth
each module and features/limitations.
4.1 Motivational Example
Android’s design and functionality has changed a lot during the course of the years, but security has
always been one of Google’s focus. With the advent of secure communications, thanks to Transport
Layer Security and its predecessor, SSL, many services once considered to critical or confidential to
be provided remotely like monetary transactions or the signature of important documents are now al-
most exclusively performed over a secure network, like HTTPS. In order to understand our solution’s
architecture and functionality, we propose the following example, based on a real world interaction.
Figure 4.1 shows a typical interaction between a client and its bank of choice, accessing it on an
Android device. Typically, these interactions are secured via HTTPS, whose underlying protocol/layer is
TLS. TLS has several steps, but essentially it is based on a key (present in a public certificate, generated
by a trusted Certificate Authority) known beforehand to the client, which is then verified and used for the
rest of the session. Assuming the client is really connected to the desired machine and that the certificate
is legit, the established session is private and secure.
However, if an attacker diverts traffic from the server to its machine and installs his own fake cer-
tificate in the client’s device (e.g., via malware), the attacker can disguise himself as the legit service,
getting the client’s secrets like his username and password credentials to the real banking service, and
provide these to the banking server, who sees him as a legit actor, as shown in Figure 4.2. Attacks like
this are not that rare. Malware toolkits like Telerik’s Fiddler can even automate them. To avoid such
attacks, server side logic and code must be hardened against spoofing, but if the user’s mobile device
is susceptible to tampering, a malicious actor can install or even replace a legitimate certificate for his
own. Therefore, it is essential secure these certificates/secrets: this is one of Locksmith’s purposes.
23
1: Generates Certificate
TrustedCA
1: Initiates TLS protocol
2: Provides Certificate
3: Secure connection
Figure 4.1: Secure authentication and communication between a user and an online banking service.
0: Connects to attacker's machine
2: Implants fake certificate
1: Initiates legit connection
3: Log in
4: Attacker can now act as the victim
Figure 4.2: Man-in-the-middle attack via certificate forgery.
4.2 Threat Model
In the section above, we described a typical Man-in-the-Middle attack against an authenticated and
confidential transaction, without going in depth on the attack vector. Such attacks take in consideration
several factors such as the victim’s behaviour and awareness, how easy is to spoof the target service,
and so on. However, our solution’s scope does not encompass the whole environment in which security
is a factor when operating an Android device (from the hardware to the application layer) – instead it fo-
cuses on the component responsible for the handling and management of client-side, security-sensitive
data, which has repercussions on the entire system. In said example, such data would be the authentic
certificates of the online banking service.
With this in mind, Locksmith aims to protect sensitive application code and secrets inside special
enclave environments by relying on a trusted hypervisor. We consider three main attack vectors:
• User space attacks: Any attack at the application or user space level – even Locksmith’s normal
24
User Apps Keystore
Keymaster(Client side)
Locker
Bao
Lockpick
KeyMaterial
Android Enclave SecureEnclave
ARM TrustZone
Figure 4.3: Locksmith architecture: its specific components are highlighted in yellow.
world counterpart – doesn’t compromise any confidential data protected by our solution, even with
a high privilege level.
• Kernel exploits: A compromised kernel may attempt to access or modify secret keys residing
inside an enclave; however, this must not be allowed.
• Attempts to break into enclave environments: The attacker may attempt to find flaws in the
interface to the enclave where the sensitive application code and secrets are located. We aim
to make the system robust against such attacks by reducing the possibility of code vulnerabilities
inside the trusted runtime environment running inside the enclave.
Locksmith’s TCB includes not only its specific components but also a preexisting trusted hypervisor.
The utilized hypervisor has the capacity for several “enclaves” to run side-by-side. These environments
have the ability to interact with each other. However, the hypervisor ensures that they can’t force or
disrupt any other environment without its permission. Thus, our solution runs enclosed inside the hyper-
visor which leverages the TrustZone, depending on its correctness. If somehow it gets compromised the
attacker may gain access to the enclave and read or modify protected keys; this attack, however, is out
of scope of this work. In addition, Locksmith does not take in consideration attacks against TrustZone
itself. We assume that the TrustZone hardware is correctly implemented.
4.3 Locksmith Overview
Our proposed solution consists of a system named Locksmith. It aims to overcome the inherent risks
with giving full trust to TEEs and undisclosed development from vendors, we started by breaking apart
each component in the complex system that is Android’s Keystore and Keymaster. As described pre-
25
viously, the Keystore is Android’s system responsible for the execution of security-related operations
and managing the life cycle of key material and ciphered data. It is where application developers make
requests via the Java API, which are then forwarded to the Keystore daemon. Confidential blob material
is actually stored here, but it’s encrypted so it can be stored but not used or disclosed. After the request
is processed by the daemon, the desired operation is sent to the “client” side Keymaster, keymasterd,
which then serializes the request in a certain format for the Secure World Keymaster.
To reduce these risks, we designed Locksmith according to the architecture depicted in Figure 4.3.
It is composed of two main elements – Locker and Lockpick – which interact via the Bao hypervisor’s
shared memory system. Starting with the Android OS, we made several adaptations to the client-side
Keymaster component, in order to deploy Locker – our “driver” component between the normal world
and the Bao enclave. Inside the enclave, runs only our main component in a bare-metal component
– Lockpick – which acts a “server” for Keymaster calls, much like the current TEE solutions. The dif-
ference being that it has no persistent storage, so the ciphered key material is entirely stored in Bao’s
protected memory region, and as described later, temporarily ciphered and saved in the normal world for
device shutdown. So, for instance, in the usage scenario described in Section 4.1, Lockpick would run
the software in change of managing the certificates and key material involved in the secure interactions
between the local mobile app and the banking server. Next, we briefly describe how Locksmith’s com-
ponents inter-operate as we follow the path of an invocation from an application running on the Android
OS to the software hosted inside the enclave, i.e.: Locker, Bao, and Lockpick.
4.3.1 Locker: Intercepting Keymaster Calls
Locker ’s goal is to seamlessly intercept invocations to the Android Keymaster without requiring changes
to applications and involving minimal changes to the Android OS. To this end, we took advantage of
the preexisting Keymaster HAL architecture. We dedicate a few lines to better explain this architecture
before we clarify how we leverage it to build Locker.
The Android Operating System is based on a modified version of a Linux Kernel, and so it follows
a Unix-like architecture. Built from the ground up, the kernel contains device drivers like input/output
and display drivers. Then, in order to provide an easier and faster way for the development and deploy-
ment of newer Android versions, there’s the HAL (Hardware Abstraction Layer), which through a special
definition language, provides a standard interface for hardware vendors to develop low-level driver im-
plementations. This removes the burden of having to maintain specific vendor implementations and
allows Android to be as agnostic as possible. Immediately after the HAL comes the System services,
which are modular, focused components like the Notification Manager or less user oriented like logcat
or netd. These services can be reached via the Binder IPC, a mechanism that allows applications to
cross process boundaries without the need of any knowledge or logic of those services itself. Finally,
in the userland is the application framework itself, where application developers can use a set of Java
libraries connected to system services like the Keystore, or even interact with the HAL itself.
The Keymaster HAL has been present since early versions of Android, and with each iteration came
26
new features, like AES and HMAC in Android 6.0. Android 8.0 introduced Keymaster 3.0, which transi-
tioned from the C programming language to a C++ definition automatically generated by a tool. Since
TEEs were already being used before, it made sense to implement the “execution” side of this compo-
nent inside one, so the interface was left in the normal world and the key content and operations were
handled inside the TEE.
Our objective was then to strip Android off this dependency, which means using the TEE as less as
possible. As so, our solution has a driver-like implementation between the client side Keymaster and
the HAL, which won’t be used any more. Locker, working as a driver, intercepts calls to the Keymaster
API and handles them accordingly, exposing its own API to the enclave side Keymaster. This API
supports most Keymaster functions and it’s strongly based on the HAL definitions. All the requests (and
corresponding responses) issued by user applications to the Keymaster will then be intercepted and
forwarded to Lockpick via the Bao hypervisor.
4.3.2 Bao: Containing Code and Data inside Enclaves
Typically, any calls to the Keymaster API would pass through the HAL, where they are serialized and
forwarded to the corresponding endpoint, which would be a TEE where the actual Keymaster implemen-
tation is in the form of a Trusted Application. These Trusted Applications depend on a Trusted Operating
System in order to have features such as attestation and secure storage. As with any Operating System,
it depends on a Kernel with direct access to the TrustZone, greatly increasing the attack vector. Our idea
is instead to allocate the Android OS and the sensitive Keymaster implementation inside independent
enclaves managed by the Bao hypervisor.
Bao [36] is an open-source embedded hypervisor, currently in development stage, that performs
static partitioning, and can leverage several enclaves – virtual machines with a 1-1 mapping of virtual
to physical CPUs, with no need for a scheduler. Since it is designed for critical systems, it focuses on
isolation for fault-containment and real-time behaviour, which is essential when performing computation
heavy tasks like public-key cryptography. Besides the required firmware, it has no external dependen-
cies which represents a small footprint on the device and an even smaller Trusted Computing Base. Its
configuration is simple and the interaction between enclaves is performed via a shared memory mech-
anism based on GlobalPlatform’s TEE Client API, which is standard in the industry and already used by
the existing TEEs, thus reducing the learning curve and enabling faster development.
Due to Bao’s architecture, the unsafe/normal world now runs entirely on an enclave alongside our
Keymaster implementation. Furthermore, Bao provides all the necessary communication infrastructure
that allows Locker to exchange messages securely with Lockpick.
4.3.3 Lockpick: Guaranteeing Functionality inside a Minimal Environment
Lockpick serves as the counterpart for Trusted Applications running inside a typical TEE, but which will
now run inside an enclave powered by Bao. Since Bao uses static partitioning, resources used by each
enclave (like memory addresses) are well-defined and can’t be altered after being deployed. Due to its
27
Host OS
QEMU
Android OS
QEMU (Limbo)
Lockpick
Figure 4.4: Initial Design
lightweight nature it can be suited to run an entire OS, complete with a kernel, or a simple bare-metal
implementation. Good performance and a small TCB are important goals of this project, and so we
developed Lockpick, the core of this entire system, with an additional concern of keeping its codebase
size small and its implementation robust.
In order to facilitate the deployment of the enclave and reducing overhead, we chose to implement
Lockpick in a mixture of C and Rust. The communication depends on the aforementioned GlobalPlatform
API, whose most stable implementation is written in C. This can be considered Lockpick’s “front-end”
component, since it exposes the internal API to the Android OS. However, the computation and storage
component is written entirely in Rust since this systems programming language is well suited to identify
possible flaws and security risks in the code itself, has a big emphasis on memory safety and a strong
type system – all enforced at compile time. No garbage collection or interpreters means its performance
is just bounded by the implementation quality and the tasks being run.
Lockpick is stateless, which means once the enclave gets shutdown (via a machine shutdown),
its execution leaves no traces behind and the allocated memory is wiped, as with any other memory
used (like the shared memory used for communication). However, we designed a mechanism to prevent
losing any sensitive material. When a shutdown signal is processed, Locker requests every key currently
being used to Lockpick, which ciphers them with its own key and proceeds to store them on the Android’s
persistent storage. At boot, Locker uploads back the stored keys via another API call to Lockpick.
4.4 Initial System Design
Before we delve into the details of our current design, we provide a brief description of how the final
Locksmith architecture came to be. The current architecture evolved from a much simpler concept,
which was trying to split Keymaster functionality as best as possible, even if it would mean still running
28
Trusted OS
Keymaster TrustedApplication
Android OS
Keystore
Service List
...
Trusted KM Device
Software KeymasterDevice
Figure 4.5: Possible Keymaster devices
most of it the insecure world. We wanted to observe the system in action, and in order to do this we
developed two prototypes first, the second one having a slight difference in the isolation method.
Software implementation of Keymaster: In older versions of Android, where TEEs weren’t as com-
mon or dedicated processor for cryptographic operations didn’t exist yet, Keymaster’s API was imple-
mented in the normal world, using OpenSSL. When it started using more advanced features like public-
key cryptography, TEEs were deployed and thanks to the HAL and its definition language, the Android
component was independent of the vendor component, and was up to the vendor to incorporate its API
implementation via a service. However, in order to provide support to older devices, the original Key-
master implementation still exists in Android’s code base. Internally, when Keystore boots, it creates a
Keymaster device which will handle requests and forward them to the corresponding implementation. A
Software Keymaster device is created when a TEE or a Keymaster service isn’t detected, as shown in
Figure 4.5. This implements the full Keymaster API but has the disadvantage of running in the insecure
Android OS, susceptible to attacks.
Creating an isolated environment inside emulated Android: Our solution targets arm64 devices
and was tested on one. Arm64 devices are becoming increasingly more common and their performance
alongside with their power consumption makes them an attractive target for Android and not just smart-
phones. However, in order to speed up the development and testing process, we first opted for an
emulated version of Android 8 that we could run on our local device. This enabled faster bootstrap-
ping and debugging, which can be quite time consuming when dealing with actual development boards.
Since this Android image doesn’t use any TEEs or special environments, the KM falls back to the original
software implementation. There are only a few virtualization options for Android and most of them have
a specific purpose, so we used QEMU to provide an environment where Lockpick could run. Figure 4.4
represents this “nested” architecture.
Splitting Keymaster functionality: In this initial prototype we wanted to understand the capabilities
and limitations of detaching the execution from the API calls and running them in a separate environ-
29
ment, completely detached of Android functionality. To do this, the first version of our main component,
Lockpick, provides support for an auxiliary function used to generate RSA keypairs. Even though it is
simple in nature, it’s analog to most of the other functions in term of dependencies/requirements.
Communication layer: As described previously, the Keystore framework gets its requests from appli-
cations, forwarding them to Keymaster, if needed (some security operations might not need, like check-
ing authentication tags). In our initial prototype, since the Software Keymaster is being used, there is no
need for a HAL or communication interface between the Keystore and KM, because they share the same
Operating System and resources. However, since actual execution of the API is being performed outside
of this environment, there still exists a need for a communication layer between the two components.
Since both virtualization (Android and Lockpick ) are happening on QEMU, we can use its default capa-
bilities and as such chose to use SSH to serve as a “wrapper” for our protocol, which will be explained
in Chapter 5.
Contained OpenSSL: Vendor implementations, or at least the ones that are publicly available (like
OPTEE and Trusty), resort to their own implementations of cryptographic libraries, as low level as pos-
sible (secure Operating Systems have practically the same resources as normal OSes, and sometimes
even a dedicated processor). Since it’s not in the scope of this project to implement from scratch well
established cryptographic primitives, we use OpenSSL as our cryptography library. This allows us to:
• Support the entirety of the underlying requirements for the Keymaster API without additional low-
level programming
• Use the comprehensive and thorough documentation of the OpenSSL API
• Easily change if needed the programming language used to build Lockpick, since it has extensive
bindings for most modern languages
Next, in the following sections, we describe our final design in more detail. We refer the reader to
Figure 4.3 which shows the final architecture of Locksmith.
4.5 System Bootstrap
When the device powers on, the modified U-boot starts the Bao hypervisor. The built-in, compiled
configuration is read and the enclaves are started automatically. One enclave for Android, which boots
normally, another for our implementation, Lockpick, and finally one that is used for shared memory
access, a space where both enclaves can read/write values. This way they can’t access one another
directly, just through the communication API which deters several possible attacks.
Depending on the target device, different processing power can be allocated to each enclave, being
the default value one core. Since Lockpick is simple enough to perform its task with just one core,
we chose to keep it this way. However, some cryptographic primitives could benefit in having more
30
Function Input Output Descriptionreload key Key type, id, hex 0 if ok Loads back a stored keystore key for shutdown Key type, id Hex Ciphers a key for shutdowngenerate key Key type Key id Generate a keyimport key Key type, PKCS8 Key id Imports a key in PKCS8 formatexport key Key id, Cert. params X509 Exports a public key in X509 formatdelete key Key type, id 0 if ok Deletes a specific key in memorydelete all keys - 0 if ok Deletes all keys in memory
Table 4.1: Lockpick API.
than one core, which would enable parallel execution for them. One core could be allocated to the
communication and another for the calls themselves, which could yield faster executions, as long as
they were properly synced. Being Keystore/Keymaster one of the first services started by Android’s
service manager, zygote, it needs to be ready early in the boot process. Since our enclave is very
lightweight with no external dependencies, once the third enclave – the shared memory – is ready,
Lockpick is ready to go.
4.6 Lockpick API
In section Background/Keymaster API we showed Keymaster’s full API. Its arguments and return values
are described in a generic way since they are based on the HAL interface definition language, which can
technically be ported to any language, but current implementation is in C++.
Lockpick’s API implements the most important functions, and the ones that make sense in our en-
vironment, which is somewhat limited due to storage and memory constraints. Table 4.1 lists our API’s
function and input/output parameters in an agnostic way, similar to Keymaster’s specifications.
Some functionalities, like adding entropy to the system (via the addRNGEntropy call) aren’t present,
since they depend on specific hardware features that might not be present in the processor being used
by Bao. Multi threading support isn’t currently available on Bao, so it is not possible to implement KM’s
concept of “operation”, as in a task that can occur concurrently with others, and like a mutex, locks
access to the object in use.
4.7 Communication between Components
As mentioned previously in Section 4.3.2, Bao has a shared memory access system based on libteec,
which is a universal API for communication with TEEs, following the standard GlobalPlatform specifica-
tion. This is a well documented and thoroughly tested library that offers several high level interfaces.
Once the communication enclave starts running, it’s possible for the other enclaves to start interacting
with each other.
These interactions are performed inside a Context. Even though we are not actually running a secure
Operating system inside the enclave, the communication library treats Lockpick as a Trusted Application,
and as such there is a Session attached to it. It is by referencing this session that commands can be
31
Android OS
Bao
Libteec Commands
TEE Client API
Locker
Shared memory
Enclave
Lockpick
Shared memory
Figure 4.6: Bao’s communication architecture
invoked. These commands are compiled unto the TA itself, and the resulting values/outputs can be
accessed via the shared memory. Figure 4.6 exemplifies this behaviour. Since both components were
built against the same interface the developer just needs to specify the memory addresses intended to
be read/written to.
Firstlaunch
New keysget
generated
Deviceshutdowns
Device bootsagain
AndroidOS
Enclave(Lockpick)
generate_key(import_key)
Plaintextkey
material,inside
dedicatedenclavememory
store_key_for_shutdown
Keys getciphered byLockpick'sKEK andsent to
persistantstorage
Lockpickonly has
itsencoded
KEK
reload_key
Keys getloaded backinto memory
Figure 4.7: Storage solution
32
4.8 Storage and Persistence of Key Material
Key material is not ephemeral and several keys can have use during the entire life cycle of a device, and
as such a safe, permanent storage is needed. Our solution abandons the traditional TEE and with it,
some native capabilities that come with secure Operating Systems, like persistent storage.
Our solution to this drawback is simple: use them as normal when the device is turned on and stored
them encrypted when it’s off. To achieve this, Lockpick has a hard coded 256 bit AES key, used as
a Key-Encryption-Key (KEK). Figure 4.7 exemplifies this behaviour. Once everything is installed in the
device, the first boot ensues, and at this point no keys are generated yet (at least in the Keystore domain,
other keys like the Master Key aren’t included). Once keys start getting created, or even imported, for
example from X509 certificates, they are temporarily in Lockpick’s allocated memory.
When the device is booted, these keys never leave the enclave’s memory. If an intent to shutdown is
detected, Locker will start making requests to Lockpick to get each key back and store it in its domain.
These keys are ciphered with Lockpick’s KEK so even if a bad actor has access to them, they can’t
be read. If modified, they will be considered invalid. Every time the Keystore starts, if there were keys
stored by Locker, they will be reloaded unto the enclave and deciphered by the KEK.
Summary
In this chapter, we provided an in-depth overview of our solution and its components, alongside their
strengths and weaknesses. Lockpick is composed of two parts, one in each virtualized environment
(enclaves). The Android component makes requests in the form of commands to the enclave which
executes them and returns the output in a shared memory, on a third enclave. The enclave itself doesn’t
have persistent storage, however the key material is protected in the normal world when the device isn’t
running and restored when it boots again, thanks to asymmetric cryptography. The following chapter
takes a look at our implementation stage and the challenges we had.
33
34
Chapter 5
Implementation
This chapter presents our implementation of Locksmith. We iterated through several prototypes be-
fore obtaining a stable one that was up to par with the Keymaster API. We targeted a ROCK960 – an
ARMv8 development board suited for the latest Android version. While building these prototypes we
went through several challenges. This chapter consists of a more practical view of the development
process and the explanation behind our technical decisions. The first section is dedicated to the initial
prototypes: we developed one first prototype, which then modified with a relatively minor change result-
ing in a second second prototype. Sections 5.2 and 5.3 are specific to the final implementation, even
though they share some similarities with the initial prototypes.
5.1 Initial Prototypes
The initial stage of this project was dedicated to learning about Android security and how the Keymaster
interacts with the Keystore and its TA counterpart running in the TEE. To achieve this, we needed to
observe, modify and debug the Android Operating System as hassle-free as possible. As so, we opted
to use a x86 port of Android 8.0, called Android-x86, and to develop our prototypes for a software-
emulated platform – deployment on a real ARM hardware board was carried out in a later stage.
In its inception, Android-x86 was just a set of different patches that enabled Android emulation on
specific x86 machines, but soon evolved to a fully fledged Android “clone”. Based on Android’s main
branch, one of the key differences is that since it runs emulated (on QEMU by default) it has no access
to hardware specific technology like the TrustZone. This initially might have seemed counter-intuitive
since most recent Android devices have TEEs provided by the hardware, however:
• this approach allows for much faster development since there is no setup/bootstrap for the hard-
ware (like flashing after each build);
• debugging is simplified, since QEMU seamlessly integrates an ADB shell;
• the lack of a local hardware-supported TEE, forces the OS to use the default Software Keymaster
implementation, which uses the same API and very similar underlying mechanics.
35
Figure 5.1: Android running Debian via QEMU.
5.1.1 Emulating Enclaves via QEMU
After choosing our target Android-x86 environment, we looked into possible isolation mechanisms that
could be instantiated inside Android OS and emulate the enclave environment where Lockpick was to
be deployed. Due to the nature of our hardware-stricken system, we were limited to software solutions.
Unfortunately, there are not many virtualization options lingering in the Android ecosystem. Most of them
are user applications that are intended to run a “containerized” Linux image, being the main purpose the
possibility of running non-mobile versions of programs like Firefox or LibreOffice.
Finally we found an app suited to our needs, called Limbo. Cross-compiled for several targets, it em-
ulates several architectures like x86 and PowerPC, through the use of QEMU. Limbo has a rudimentary
interface, since it’s essentially just a front-end for QEMU on Android. Thus, we use Limbo to emulate
an enclave in the form of a virtual machine managed by QEMU. Before we could Lockpick inside this
emulated enclave, the virtual machine needed to be configured with a guest operating system image.
For practical reasons, we picked the latest Debian “lite” image available to run in the enclave. This im-
age allows us to have similar kernel versions both in the host (i.e., Android-x86) and in the guest (i.e.,
inside the enclave). Using QEMU also allowed us to establish a communication channel between both
these components without large performance overhead or more complicated setups. Figure 5.1 shows
a screenshot of Limbo creating an instance of a Debian virtual machine inside Android.
5.1.2 Communication between Software Keymaster and the Emulated Enclave
In the first prototype, we just wanted to perform small exchanges between the Software Keymaster run-
ning in Android-x86 and our isolated enclave-emulated environment. QEMU has native port forwarding
36
Figure 5.2: Initial protocol’s main loop.
which maps a guest port to a host port, and also socket support, which opens UNIX like sockets in both
systems. Android manages resources very strictly, and a socket would be to complex for what we intend
to do, which is simple message passing. Therefore, we chose TCP for the transport layer. Since parsing
raw TCP packets from scratch was out of the scope of this project, we picked SSH has a “wrapper” for
our basic API-like calls. SSH is a proven, secure communication protocol that works out-of-the-box on
both Android and Debian, our guest machine.
In order to maximize the performance and not encumber the development with external dependen-
cies, C was the programming language of choice. It features a powerful compiler and complete control
over resources. There are currently two C SSH libraries: libssh and libssh2. The first one is the oldest,
and can work both as a client and a server. The second one is newer and can act only as a client,
which doesn’t fit our requirements. We then developed a simple protocol (Figure 5.2) for communication
between Android and our “pseudo enclave”. The first part is just the normal establishment of a SSH
session, entirely via libshh. After that, a BEGIN string is expected to be received, after which it waits
for one of the available commands. A simple logging framework was developed since libssh only logs
37
Figure 5.3: First prototype’s structure.
SSH-specific events. Along with some serialization testing commands, we were able to execute and
successfully run some commands from the OpenSSL 1.1.1d API.
5.1.3 Modifying Android Modules
Our final step in this first prototype was to enable us to intercept the calls issued by Android applications
to the Software Keymaster so that we could later forward such calls to the emulated so as to be served
in the future by Lockpick. To this end, it was necessary to modify some Android modules which was one
amongst the most laborious tasks of this project.
Android’s source code is structured based on compartmentalization. Sources are grouped into mod-
ules, which is either a static library, a shared library or a standalone executable. In our case, we need a
mixture of these elements, especially having an external library – libssh2. This library is relatively easier
to use compared to libssh, and we just need client features on the Android component. In order to use
libssh2, we created a module system/libssh2. system/ contains the main modules that make up the
Operating System, like Keystore and Keymaster. Initially we tried to use libssh2 as a shared library, and
for such we compiled its dependencies, OpenSSL (as a shared library too) via the Android NDK version
21. This was a lengthy process since we had to manage conflicts between shared dependencies of
the Android target and our own machine, and unfortunately we could not use it as a shared library. By
switching to a static build we were able to import it as a library for the main Keymaster module.
In order to run our test commands, some slight modifications to Software Keymaster were made in
order to call our functions. We were able to establish a successful interaction between both components.
Figure 5.3 shows all files that were added or altered in this development. This set of modification has
concluded our first prototype. Next, we explain how we have developed our second prototype, and then
how it was deployed and tested on several different environments.
38
5.2 Locker Implementation
The initial prototype just described served as a testing ground for the second prototype which includes
the implementation of Locker and Lockpick. This section describes the implementation of the former,
and Section 5.3 the implementation of the latter.
For our implementation of Locker, we first targeted the enclave emulated setup based on QEMU
described above. This logic didn’t change much after the replacement of this emulation scheme with the
Bao hypervisor, just the environment and communication channels. However, as stated in the sections
above, we initially used an emulated version of Android that was stripped off its hardware capabilities
like the TrustZone, which our Bao hypervisor depended on. On a real device, especially one running the
latest Android, this would not be the case, being highly likely the present of dedicated TEE hardware.
To incorporate Locker into Android OS, we proceeded as follows. Google’s master branch, on which
vendors base their implementations, provides the HAL for each component and its up to manufacturers
that have their own flavour of Android to implement a service that uses the HAL as a bridge for its
implementation. In order to avoid adding unnecessary complexity and having to add SELinux policies,
we did not go through this route and simply disabled our Android’s TEE solution, OPTEE. OPTEE is
an open source Secure Operating System common to many Android devices, especially development
boards. This way, Keystore defaults to the Software Keymaster which has our Locker component acting
instead of it. Next, we describe the main steps of how Locker was implemented.
5.2.1 Choosing a Design Pattern for the Locker Code
After disabling the external TEE Keymaster, we wanted to implement actual API calls instead of some
partial operations performed by OpenSSL. The first prototype had our logic implemented by modifying
already existing calls. Since the Software Keymaster is a legacy option and is not up to par with the
current implementations, Keymaster 3 and 4, we wanted to create an interface to our enclave counterpart
that was light, unobtrusive and simple to use.
After examining the rest of the Keymaster module, we found that the code adhered to a design that
was overly complicated for what we were trying to achieve. The majority of the OS is written in C++, with
some C features enabled, so there were plenty of options for the architecture. As a result, we ended up
choosing a Singleton pattern for Locker. This was based on the fact that:
• only one Keymaster runs at any time;
• it assures proper creation and destruction of the corresponding object;
• it keeps the implementation simple and clean.
A short snippet of Locker’s code is shown in Figure 5.4.
39
Figure 5.4: Locker singleton object.
5.2.2 Handling Keymaster API Requests
Although not shown in the code listed in Figure 5.4, Locker implements the main components of the the
Keymaster API. Essentially, it forwards all the requests transparently to the enclave. Now that the “client”
side logic was implemented, we needed to be able to communicate with the enclave. When emulating
enclaves using QEMU, we used the communication channel described in Section 5.1.2.
However, when replacing our QEMU-enabled enclaves with enclaves powered by the Bao hypervisor,
we performed additional chances. In particular, we integrated our Keymaster API inside Bao’s “applica-
tion” layer, which is heavily based on libteec. Our methods and parameters had to be wrapped around
specific structures, in order to perform TEE-like calls to the enclave. This was an ongoing process as
we had to tweak several times the API, since both sides, Android and secure world enclave, most use
exactly the same interface. In order to call our enclave/TEE-like commands we did a static build of the
library and similar to libssh2, created a module and imported it.
5.3 Lockpick Implementation
Lockpick was initially implemented and tested for an enclave that was emulated by a virtual machine
managed by QEMU. As described above, this virtual machine was running Debian. However, for our
40
second prototype, we needed to find an alternative that would not require the deployment of a full-blown
Linux kernel inside the enclave as this approach would bloat the TCB. Thus, during this process, several
possibilities for the environment in which Lockpick would run were considered.
In particular, fully fledged operating systems, like how Debian was used for the initial prototype, were
quickly discarded as an option since they are too heavy on the system’s resources, and most of what
they provide are completely unnecessary to our implementation. As an alternative, lighter options like
Buildroot – an automated tool that generates an embedded Linux image were also considered, but even
an image as stripped down as possible still represents too much overhead. Our final solution consisted
of extending a basic application developed for Bao. The Bao hypervisor is still in heavy development. It
had to be adjusted several times during this process, by the team at Universidade do Minho, in order to
work on our target device. The Bao team initially developed a simple “Hello World” like application, which
we used as a baseline for our implementation. It was linked statically to basic dependencies like libc,
and its memory had to be initialized manually. This need of speed and fine-grained resource allocation
supported even more our decision to use Rust as the main component of our Keymaster implementation.
5.3.1 Implementing Lockpick as a Rust Library
Rust was chosen as Lockpick’s “engine” even though our small prototype codebase was in C. It has
a strong type system and emphasis on memory safety which we deemed crucial to a system-critical
application like Keymaster.
Since almost all Keymaster’s operations are cryptographic, we first analyzed several libraries and
frameworks to use. Options like ring and sodiumoxide seem sound at first, but both lack asymmetri-
cal encryption, which is one of the main types of encryption used. Rust is a relatively new language
and even though it has a strong community and development ecosystem, there still isn’t a completely
mature cryptography library. Due to this, we used Rust’s bindings for OpenSSL, a crate which can call
OpenSSL’s API and even has the capabilities of downloading, building and embedding a static copy of
OpenSSL, through the vendored feature. This way, there was no need to have a special setup in the
enclave since OpenSSL was already linked to the Rust library. liblockworker, our Rust library, had to
adapt to its environment, which would be very bare-metal. The lack of persistent storage in the enclave
led us to a memory based implementation, by storing the keys directly in memory, as seen in Figure 5.5.
The API itself is implemented in a straightforward fashion, as simple as possible. In Figure 5.6, we
present the implementation of the import API call. Note the use of the unsafe Rust tag, needed in order
to communicate values back and forth between its C counterpart. Since this is the only application
running inside the enclave, there is no risk associated with using the unsafe tag. Even with the Key-
Encryption-Key present in memory and the used IVs, this memory is completely out-of-bounds from the
rest of the system, and is only readable and writable to the enclave itself. Our API was relatively simple
to test – thanks to the existing Softkeymaster implementation, and since we were also using OpenSSL,
we could easily compare the results between the two implementations.
41
Figure 5.5: liblockworker’s basic state
5.3.2 Lightweight C Binary
Now that the functional part of Lockpick was finished, all that was left was “packaging” everything so
that it could run and communicate outside our enclave. As referenced previously in Section 5.2.2, there
are currently no Rust ports of libteec, which is what Bao’s communication API is based on. Since the
code written in C would only serve to serialize and pass values between Locker and the Rust library, it
wouldn’t compromise any of the sensitive operations performed.
Bao’s implementation is entirely written in C so there was no need to write bindings of any sort. Rust
has the possibility of interoperability with C code, which is performed by specifying a system ABI with the
extern ”C” keyword. The no mangle annotation also tells the compiler to not mangle the following block
of code. These two features combined allow for an external C application to call the specified functions
(shown in Figure 5.6), if its arguments and return values are specified. The process of converting native
C types like integers and pointers is facilitated by a tool called cbindgen, which scans Rust source code,
looks for the annotations/tags previously described and generates a C header file with the corresponding
function headers. The last step is compiling everything as one would normally compile a C application
and binding statically against our Rust library, which has OpenSSL already embedded. Figure 5.7
summarizes this entire process.
5.4 Locksmith Deployment
We now discuss the main aspects related to the deployment of Locksmith. In particular, deploying
Lockpick requires several phases, independent of where it will be isolated, whether in a Bao enclave, or
running on the same machine locally with QEMU. In the following sections we present the deployment
process, albeit a resumed version, since our solution requires modifying every layer of our target device,
from the bootloader to the Operating System (of each Bao enclave). Our target device, shown in Figure
5.8, has a set of ports and peripherals that facilitate the deployment and debugging process.
42
Figure 5.6: The import function and unsafe tag
5.4.1 Deploying Locker
We built Locker using the Android 9 tree. Specifically, the Box image, an image intended to be used on
Android TV devices, which was the only working image provided for the ROCK960. Unfortunately, we
tried older images in order to have a codebase similar to Android-x86, but the only maintained public
repositories had several bugs and development wasn’t active anymore.
This is the step also where we “inject” our Keystore testing application, simply by putting in the vendor
directory, which is where system applications reside. Doing this accelerates the testing process as we
don’t have to reinstall it every time we make a modification to the system. Compiling an Android image
is a lengthy process, and every time we performed the slightest modification to the system, we had to
recompile parts of it, which was quite time consuming. Due to bigger priorities and time constraints, our
Locker “module” has to be inserted directly where the client side Keymaster resides. This is achieved by
adding our single C++ class, modifying the Keymasters “.bp” file, which is Android’s flavour of a Makefile,
and adding the corresponding communication layer libraries, libssh or libteec, depending on what is
being used. After this is done, Android’s build script produces several partitions of the system. We are
specifically interested in the gpt one, since it contains the main system components, like Keymaster.
5.4.2 Preparing Lockpick
Building Lockpick is a different process. Half of it, liblockworker can be compiled in a standalone fashion
with Rust’s compiler, independent of the chosen communication mechanism, since it’s linked against the
C counterpart and communicates via the binary’s shared memory, as exemplified in Figure 5.7.
43
lib.rs (andsmaller
dependencies)
OpenSSLcrate
rustc
liblockworker.a
lockpick.c
libteec.so
Makefile
lockpick.h
cbindgen
gcc
lockpick
Figure 5.7: Lockpick’s build process
Now, if the target environment is a local, emulated environment, libssh needs to be manually com-
piled and linked against Lockpick and the Rust library. All libraries should be compiled statically, in order
to avoid any dependency problems on the target machine, which also enables a seamless switching of
architectures/devices for testing.
Since it is part of the enclave itself, Lockpick must be compiled unto the enclave image, which is a part
of the Bao system. Bao works immediately above the hardware layer, so some firmware modifications
are required and the device’s bootloader (our target device uses U-Boot) must be configured to launch
it which will then start the enclaves according to their configurations.
Finally, the Android image must be first flashed (typically only the main gpt partition is needed),
followed by the modified Bao partitions. This entire process is applicable to any application deployed
on a Bao enclave and not exclusive to Locksmith. To ease this whole process we wrote a script which
compiles both Lockpick and Bao, setups our development board for flashing, flashes it and reboots it
into the new system.
5.5 Issues with Bao Integration
Both Locksmith-specific components – Locker and Lockpick – were ready to be deployed as stated in
the previous section. In the very early stages of this project, we had already modified the Android OS
for running on our target board (see Figure 5.8), without any issues arising. However, targeting the
board was soon proven to be much slower than developing in the QEMU version of Android, being,
nevertheless, our final target.
44
(a) front (b) back
Figure 5.8: ROCK960 development board.
Unfortunately, Bao was not entirely stable throughout the duration of this project, and there were
numerous configuration and deployment obstacles with our target machine and implementations. Due
to these factors, coupled with time constraints, we weren’t able to deploy our final prototype using Bao
and its enclave system on the board.
Summary
There were several challenges implementing our solution. Most were due to the complexity and number
of different systems that it makes use of. Due to the enclave’s resource constraints everything had to
be as lightweight and simple as possible, while guaranteeing functionality and safety. This chapter has
described the implementation process, and the challenges that we had to face and how we overcame
them. The next chapter presents our experimental evaluation performed and the results obtained.
45
46
Chapter 6
Evaluation
In this chapter, we present our experimental results. The previous chapter detailed some of our short-
comings, the main one not being able to use Bao’s enclaves. However, we are still capable of comparing
our minimalist Keymaster implementation with existing ones, such as the Softkeymaster implementa-
tion, in terms of performance and resource usage. Section 6.1 lists our main objectives and metrics
used for evaluation, while Sections 6.2 and 6.3 show the results of these two measured aspects. Finally,
Section 6.4 analysis some security aspects of our implementation.
6.1 Evaluation Objectives
Our main goals with this experimental evaluation are to measure the difference of overall performance
and resource usage against the current existing Keymaster implementation and architecture. Even
though the current Locksmith prototype provides a simple implementation of the Keymaster, it features
its essential API functionality without needing a fully fledged TEE or OS.
Since the Keymaster is not exposed directly to the user nor to a regular application developer, it’s
not possible to directly evaluate its impact on the overall usability and user experience, since it doesn’t
concern these domains. However, traditional measurements like speed can still be performed accurately.
Due to the impossibility of deploying our implementation on a Bao enclave, we are limited to an
emulated environment and a development similar to what we originally intended to run on. However, we
can assess with some certainty that the values we obtained in both our benchmarks won’t differ much
from the intended environment (apart from the communication), since at this level architecture and code
quality have a higher impact than Bao’s lightweight impact and the target board’s capabilities.
With this in mind, we also take a look at a less obvious and direct parameter of our implementation,
which is overall security of the system. Once again, we have to perform a simple analysis on our system
and strengthen it with the already given security guarantees of the Bao hypervisor, since these two
system overlap as intended.
47
6.2 Performance
As described in the previous section, we established different setups and environments in order to have
an approximation to the intended final system as close as possible. Like Chapter 5 mentioned, our main
environment development was an emulated, x86 version of Android 8.1, called Android-x86. This OS
features the latest Keymaster architecture in use and its last software implementation, which is much
simpler to understand and modify for testing purposes. It also runs on QEMU, which is has a small
overhead and footprint on the system, and allows us to tweak parameters like CPU core usage and
available memory to the system.
We split this section into two different views of the system, in order to perform a fine-grained evalua-
tion of the system: the first, which we deemed as “Global”, analyzes the overall impact on the usability
of the system, taking into account just the impact on a macro level of the whole OS, while the second
group, named “Micro”, performs measurements just at the implementation level, disregarding the normal
context in which it usually operates.
It is important to note that all of these tests were realized using our own communication mechanism
and not Bao’s, due to its unavailability at the time of writing, which means the actual values would be
lower in theory (according to our personal and the team’s assessment).
6.2.1 Global Benchmarks
To evaluate our implementation with typical workloads, we had to force Keymaster calls. Since they
can only be evoked via the Keystore, we compiled an application used to test the Keystore developed
by Google. Due to architectural changes in Android 10, this application no longer works in the latest
Android, however we were able to backport it to our target version, 8.1, as shown in Figure 6.1.
Our main metric for performance is completion time, which is the time needed to perform a normal
workload, from start to finish. We measure this by using the standard time C library and its time and
timediff functions which allows us to get a duration in milliseconds of the workload tested. An example
of this is shown in Figure 6.2, using the API’s default GenerateKey implementation.
It is important at this point to remember Locksmith’s proposed architecture and the communication
layer we used while developing and ultimately for the final prototype. As shown in Figure 4.6, the
communication mechanism between both components, Locker and Lockpick, is performed by Bao’s
shared memory mechanism. At this stage integrating with Bao was deemed impossible, so we resorted
to our initial communication layer via SSH. To simulate the enclave counterpart, we ran Lockpick waiting
for commands on an open SSH port in the same machine, which features an Intel i5-8250U CPU (8
cores, 4 physical) and 16 GB of memory, running Ubuntu 20.04 (64 bit).
The application used to test, represented in Figure 6.1, provides the 3 most common operations
which are key generation, signing and verifying a signature, all performed on the same entity. We used
our time difference technique to instrument the operations responsible for these operations. However,
Keymaster is not responsible for some of these operations. Instead, Keystore calls some parts of it,
like obtaining key material to perform signatures. Due to this fact, part of the numbers displayed will
48
Figure 6.1: Keystore testing Application.
also account for operations not performed by our implementation, and compared the system running a
normal Keymaster implementation to our own.
Operation Normal Locksmith
Create 0.0020 0.0200Sign 0.005 0.0120Verify 0.009 0.0117
Table 6.1: System’s global benchmark.
Table 6.1 shows our results. As expected, our implementation has higher completion times, even
though they don’t deviate much in terms of order of magnitude. While performing these tests, we didn’t
observe any noticeable slowdown, apart from some delay in adb while logging the calls to Keymas-
ter. We primarily attribute these higher times to the communication layer which depends on an SSH
handshake completion before Lockpick gets any requests and executes them.
Occasionally we had some crashes, which we attributed to how Android handles the SSH connection.
Since the protocol is not being performed at an application level but rather at the system level via the
SSH library, this sometimes triggers some alarms with Android’s policy mechanism, SELinux. Our first
49
Figure 6.2: Simple speed measurement.
choice for enabling communication wasn’t SSH but raw sockets. However, we found that opening them
required heavy modifications to SELinux and it would be harder to develop a protocol on top of it.
We also note that this particular experiment wasn’t much flexible in terms of what it could explore.
These 3 operations represent the most common ones but they are static in a sense that the data they
are manipulating is always the same and the arguments never change. A good improvement would be
modifying the application’s source code in order to test several types of keys and key sizes.
6.2.2 Micro Benchmarks
Our global evaluation of the system provides a good first analysis of the design and implementation of
our system. The results we had give strength to the hypothesis that the communication layer is what
has the most impact on the performance. To find out, we analysed the time it took to establish an SSH
session between Locker and our local running instance of Lockpick.
This was performed in a simple fashion: Locker gets instantiated, performs the typical session es-
tablishment and pings Locksmith, which replies back. We measure both ends in order to establish a
Round Trip Time, but the main segment we are interested in is the protocol handshake, since after this
step there is little overhead on the communication.
Table 6.2 confirms our suspicions that the communication establishment is the main bottleneck. “Initi-
50
Step Time (ms)
Initiate Protocol 3Session Established 8Pong 9
Table 6.2: RTT/Communication establishment benchmark.
ate Protocol” refers to the point where most of the initial SSH protocol starts (port binding, authentication
methods exchanged and authentication is performed) and “Session Established” means it is ready to
communicate. libssh first creates a channel to accept connections and then it establishes a session with
the client, which in theory allows multiple streams inside one channel. Being the difference between the
last protocol step and the reply (Pong) just 1 millisecond, it is in fact the SSH bootstrapping that takes up
most of the total duration. This in theory would be negligible with Bao’s shared memory access, much
faster than relying on a complex Application Layer protocol.
With these values established, all that is left to determine is the API’s performance isolated in its re-
spective environment. This means analysing each API call one by one with no communication overhead.
This is possible by calling directly each Lockpick function directly on the C “server” that handles requests
to the Rust library and instrumenting them to get their duration. In order to get more “realistic” values,
we compiled Lockpick to the ARM64 architecture similar to our target ROCK960 development board and
performed the same tests on Raspberry Pi 4 model B. We use the Softkeymaster implementation as a
baseline and compare it against these two different setups.
All generate import export delete store reload
0
5 · 10−2
0.1
0.15
0.2
Tim
e(m
s)
Original Local RPI
Figure 6.3: Micro/API benchmarks.
51
The bar labels in Figure 6.3 correspond to the Android implementation, the local Ubuntu 64 bit
environment and the Raspberry Pi ARM64 environment, respectively. The first X axis label, “All”, refers
to a typical workload inside Lockpick itself, mainly simulating the life cycle of key, from creation to usage
and proper storage and destruction.
Without the communication layer and just the raw API calls, we observe that our implementation is
quite similar to the original one in terms of speed. It is important to note that these values don’t represent
single function calls, but averages of several iterations of different orders of magnitude, in order to obtain
meaningful values. Some of the arguments themselves were tweaked, for example while generating a
new key, we tested for both symmetric and asymmetric keypairs.
In fact this means that we had to resort to very big, somewhat unrealistic workloads, in order to
get discernible values, which strengthens our argument for this reliable and fast alternative to current
Keymaster alternatives. We can observe a slightly worst performance on the Raspberry Pi, which is
expected since it has weaker hardware and an overall slower architecture compared to x86.
6.3 TCB Size and Memory Footprint
While developing Lockpick, we strove for a minimal TCB and overall codebase. Working with C and Rust
is a double edged sword in the sense that it allows for very fast code at the expense of security, in the
form of bugs or unwanted erratic behaviour, which is a huge risk for a component as critical as KM.
In particular, we aimed for a small, yet reliable and fully functional implementation of both system
counterparts. Locker, as previously mentioned, features no external dependencies apart from libssh,
and if integrated with Bao, it would use libteec to use the shared memory access, which is a battle-
tested and reliable library. Lockpick was also made to be as less complex as possible, being essentially
a “wrapper” to the embedded OpenSSL library, featuring easy to understand code. The C half of this
binary is also quite trivial, acting as server listening for API requests.
Language Files Lines Blanks Comments Code
C Header 2 178 18 19 141C 1 424 72 6 346C++ 1 146 29 0 117Rust 1 295 31 19 245
Table 6.3: Locksmith codebase statistics
We present our statistics on the developed code in Table 6.3. Some of it is boilerplate code like
the testing framework and SSH functionality, but overall it is much smaller compared to our chosen
implementation of reference, Softkeymaster. These programming languages come with great, mature
tooling which we used to optimize further our final implementations, in order to have smaller and faster
binaries. Using rustc’s build flags, which can be set to either “debug” or “release” depending on the
target environment, and gcc’s “Optimize Options”, we were able to strongly reduce our footprint on the
enclave, which is vital since each one only has a CPU core.
52
Our initial “debug” version of the Rust library was 64.7 MB in size, quite large since it was not
optimised and featured a static embedded version of OpenSSL, but after using the “release” build flag it
was now 24.2 MB, cutting almost a third in size. This may seem big but it features everything it needs to
run by itself in the enclave or another isolated environment, without any dependencies such as an OS.
While collaborating with the Bao team, we thought of several setups for the enclave. From fully
fledged Operating Systems, like the Debian “lite” image we used in the first prototype, to minimalist,
kernel only systems (via the Buildroot tool, for example). Their initial experiments with applications more
complex than a simple bare metal “Hello World” yielded good results, but had to be thoroughly tweaked
and still had several bugs which couldn’t be present in such a system critical application like ours.
6.4 Security Analysis
Security wise, we wanted to achieve at least the guarantees provided by the current Keymaster imple-
mentation, like ciphered material isolation and no possibility of tampering the code, as a starting point.
By running our main component, Lockpick, in a completely isolated environment provided by the Bao
hypervisor, we guarantee these two essential points.
Even though it’s a much smaller implementation compared to typical TEE Keymasters, Locksmith
practically exposes the same API, so in this sense it’s subjected to possible flaws of the Keymaster
architecture itself. However, this security component has been present and used since much older
Android versions, and we believe most flaws with the API architecture have been worked out by the KM
team. With this in mind, we now present both strong points and weaknesses of our implementation.
6.4.1 Effective Security Guarantees
A malicious actor typically starts by targeting the Operating System. In older Android versions, this
meant that the Keystore and Keymaster were exposed to these adversaries and could get tampered,
eventually leaking keys or even ciphered, sensitive material directly to the attacker.
In recent Android systems running TEEs, this is much harder to achieve, however still possible as
some attacks have shown. It is harder since the secure material isn’t present in the same world as the
Operating System, and sometimes resides in a different processor/chip, but due to proprietary kernels
and code not audited publicly adversaries can still find a way through firmwares or side-channel attacks
if it is different hardware.
Our Bao hypervisor makes sure the memory zone where our enclave resides is inaccessible and
even further than that, guarantees that the allocated CPU core is exclusive, which makes it impossible
for any attacker to reach it. With no TEEs running in the machine, an attacker can only target the OS,
which has no way of directly obtaining the protected material. When the system is offline, as explained
in Section 4.8, we use the following system as to not lose any information (Bao enclaves are stateless,
there is no permanent storage):
• Store function gets called on shutdown.
53
• Every key is ciphered by the private KEK, hardcoded into Lockpick.
• Ciphered keys are stored in Android’s permanent storage.
• On boot, reload is called and transfers the keys back to Lockpick, which get deciphered.
This scheme is simple enough to not have any significant system overheads (as demonstrated in
Figure 6.3) and provides a safe persistent storage to overcome this Bao limitation. Unless the KEK gets
compromised, any tampered keys will get rejected by Lockpick, rendering these type of attacks useless.
6.4.2 Non mitigated attacks
Even with our reduced Trusted Computing Base, there are some attacks that the system is vulnerable to.
Attacks like Denial-of-Service fall off the scope of this project but are still worth mentioning. An adversary
that compromises the entire Operating System and changes Locker behaviour could in theory spam bad
API calls in order to stutter or even crash Lockpick, which currently Bao can only start an enclave at boot.
Bao could also be targeted by this method, if calls to its monitor were intercepted and altered, which is
a highly unlikely scenario.
Furthermore, like previously described, the lack of a better permanent storage solution exposes us
to another type of Denial-of-Service attack that could render the entire system useless. To perform this,
an attacker would need to:
• Intercept the store call on shutdown;
• Capture the ciphered keys’ hex code and modify them;
• Once the system is back on, replace the stored hex data with fake/garbage data, before reload
gets called
In fact, the first step is entirely optional, since merely corrupting the key files on the boot stage would
lead to a faulty reload call, which would render the existing keys useless. This, however, requires that
the attacker has full access to the Operating System, since it depends on reading/writing permissions on
the “system/” partition and intercepting the shutdown/boot call. To deter this, an attestation mechanism
would be enough in order to verify the integrity of the key files.
Summary
With this chapter we presented our experimental results and described our evaluation process, assess-
ing how it stands up against the current implementations, both performance and security wise. Different
scenarios and workloads were evaluated, in order to have a broad spectrum of results. In the next final
chapter, we finish this report by outlining our conclusions and presenting possible future work.
54
Chapter 7
Conclusions
Even though Locksmith is not mature enough to be deployed at a production level, in its current stage it
provides several arguments for its usage as a solid alternative to the current TEE Keymaster architecture.
Since it does not implement the entire current Keymaster API, apart from the essential functionalities, it
cannot still fully replace the existing system on an Android device.
On one hand, it is quite easy to build the main application for any Android device since it lacks any
dependencies apart from the embedded OpenSSL library, which gets automatically built and linked in
the build process. On the other hand, the ”driver” component, Locker, is just a small stub that needs
to be ”injected” in each Keymaster call from the client/Android side. This means directly modifying
the Keymaster module which might interfere with Android’s security policies, via SELinux, which most
devices have set to the highest security level.
Performance wise, due to its size and low degree of complexity, it performs on par with current
Keymaster systems. Even though we didn’t test it against in an environment using a Trusted Execution
Environment, we can safely assume it’s as fast or even faster, since our comparison against a local,
“soft” Keymaster yielded very similar results. Systems that use proprietary TEEs are quite hard to debug
and evaluate with our metrics since it requires directly altering them, and we couldn’t perform such a
fined grained evaluation due to this.
Ultimately we weren’t able to deploy our final prototype with the Bao hypervisor, however everything
is in place for it and thanks to our evaluation without the current main burden – the communication layer
– we can conclude the project was successful in attaining its goals.
7.1 Achievements
Our project achieved many of the intended goals, although not all of them. Even though our API doesn’t
fully match the current Keymaster’s, due to some restrictions that were out of our scope (e.g., lack of
persistent storage inside the enclave), it provides the essential functionality needed for most typical
operations used by the Keystore. On the Android side, we provide the OS with a simple interface to
interact with our system, via the Locker driver. Its simple structure and life cycle allows for any developer
55
to quickly understand how it works and modify it without breaking any other part of the system.
On the protected/isolated environment side, our implementation is swift and simple. Albeit not perfect,
the Rust programming language already takes care of many bugs and errors that could possibly appear
had we done it with another systems programming language, like C. That we know of, this is the first
Keymaster implementation written in a language other than C/C++, and makes an interesting case study
for it. Google has also recently pushed a Rust compiler and other tools to its main Android repository,
which signals their interest in this new language.
The prototype communication layer took a lot of effort since it was essentially writing another protocol
above SSH, and ultimately it would be replaced by the TEE Client library used by Bao’s shared memory
access. The way it was written, however, already contemplated the message-passing system that the
TEE library and Bao uses, so it could be quickly adapted without any major disruptions.
Nevertheless, even without being able to deploy Locksmith on our intended environment – the Bao
hypervisor – we think the following goals have been attained:
• Isolation and total separation of protected sensitive key material and the normal world.
• No dependencies on Trusted Execution Environments or proprietary vendor technology.
• Successful and safe application of the Rust programming language in order to strengthen our
system.
• Simplicity to understand and modify our API.
• Overall great performance, on par with current implementations.
We conclude this thesis by elaborating on several interesting directions for future work.
7.2 Future Work
Many challenges appeared during the implementation phase, and some even while drawing the archi-
tecture for Locksmith. Through the several iterations of our prototypes we noted several features and
improvements that could greatly improve the project. Our main goal of course was to develop a version
as stable and functional as possible with every component, from the OS to the Bao enclave.
Starting with the Operating System, the code quality and practices aren’t the best. Other parts of
Android development are quite well documented, however the OS itself is not the case, and the only way
to learn is to read code/commentaries, which affected the development process. To follow the correct
Android philosophy, our Locker implementation should be a service, defined by a ”.rc” file, which would
start at launch in an orderly fashion by the process manager, zygote. It would interact with Lockpick via
the Keymaster HAL, and our arguments would have to be adjusted in order to use this interface common
to all Android devices (which can easily be done thanks to a tool that generates these stubs).
Bao also provides several security mechanisms that could be explored. Apart from the creation
and destruction of enclaves, it has a controller used to switch the execution context that in the future will
56
provide an attestation mechanism. This is essential in guaranteeing the systems integrity, since currently
our Lockpick binary has the Key-Encryption-Key hardcoded. We could leverage this mechanism to check
on every boot if our binary has changed, or even further, if the stored ciphered keys have been tampered
with. This way we would immediately know if the system has been compromised, and the device would
react as is typical in such cases (normally locking the bootloader).
57
58
Bibliography
[1] H. Khan and A. Das. Security behaviors of smartphone users. Information Management & Com-
puter Security, 2016.
[2] A. Mylonas, A. Kastania, and D. Gritzalis. Delegate the smartphone user? security awareness in
smartphone platforms. Computers & Security, 2013.
[3] S. Egelman, S. Jain, R. S. Portnoff, K. Liao, S. Consolvo, and D. Wagner. Are you ready to lock? In
Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications Security,
2014.
[4] M. Alsaleh, N. Alomar, and A. Alarifi. Smartphone users: Understanding how security mechanisms
are perceived and new persuasive methods. PloS one, 2017.
[5] R. Mayrhofer, J. V. Stoep, C. Brubaker, and N. Kralevich. The android platform security model.
ArXiv, 2019.
[6] D. Cerdeira, N. Santos, P. Fonseca, and S. Pinto. Sok: Understanding the prevailing security
vulnerabilities in trustzone-assisted tee systems. In Proceedings of IEEE Symposium on Security
and Privacy, 2020.
[7] K. Mindermann, P. Keck, and S. Wagner. How usable are rust cryptography apis? 2018 IEEE
International Conference on Software Quality, Reliability and Security (QRS), 2018.
[8] ARM. Introducing the ARM architecture, 2019 (accessed December 21,
2019). https://developer.arm.com/architectures/learn-the-architecture/
introducing-the-arm-architecture/single-page.
[9] S. Pinto and N. Santos. Demystifying arm trustzone: A comprehensive survey. ACM Comput. Surv.,
2019.
[10] J. Ramos. TrustFrame, a Software Development Framework for TrustZone-enabled Hardware,
2019.
[11] N. Santos, H. Raj, S. Saroiu, and A. Wolman. Using arm trustzone to build a trusted language run-
time for mobile applications. In Proceedings of the 19th International Conference on Architectural
Support for Programming Languages and Operating Systems, 2014.
59
[12] Y. Zhou, X. Wang, Y. Chen, and Z. Wang. Armlock: Hardware-based fault isolation for arm. In
Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications Security,
2014.
[13] D. Sehr, R. Muth, C. Biffle, V. Khimenko, E. Pasko, K. Schimpf, B. Yee, and B. Chen. Adapting
software fault isolation to contemporary cpu architectures. In Proceedings of the 19th USENIX
Conference on Security, 2010.
[14] L. Zhao, G. Li, B. De Sutter, and J. Regehr. Armor: Fully verified software fault isolation. In 2011
Proceedings of the Ninth ACM International Conference on Embedded Software (EMSOFT), 2011.
[15] S. Pinto, D. Oliveira, J. Pereira, N. Cardoso, M. Ekpanyapong, J. Cabral, and A. Tavares. Towards
a lightweight embedded virtualization architecture exploiting arm trustzone. In Proceedings of the
2014 IEEE Emerging Technology and Factory Automation (ETFA), 2014.
[16] AOSP. Application Sandbox, 2019 (accessed December 21, 2019). https://source.android.
com/security/app-sandbox.
[17] AOSP. Discretionary Access Control (DAC), 2019 (accessed December 21, 2019). https:
//source.android.com/devices/tech/config/filesystem.
[18] MITRE. CVE-2017-0322, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2017-0322.
[19] N. Elenkov. Android Security Internals: An In-Depth Guide to Android’s Security Architecture. 2014.
[20] J. Ekberg, K. Kostiainen, and N. Asokan. The untapped potential of trusted execution environments
on mobile devices. IEEE Security Privacy, 2014.
[21] J. Jang, S. Kong, M. Kim, D. Kim, and B. Kang. SeCReT: Secure Channel between Rich Execution
Environment and Trusted Execution Environment, 2015.
[22] W. Huang, V. Rudchenko, H. Shuang, Z. Huang, and D. Lie. Pearl-tee: Supporting untrusted
applications in trustzone. In Proceedings of the 3rd Workshop on System Software for Trusted
Execution, 2018.
[23] MITRE. CVE-2014-4322, 2014 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2014-4322.
[24] MITRE. CVE-2015-4421, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2015-4421.
[25] MITRE. CVE-2015-4422, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2015-4422.
[26] MITRE. CVE-2015-6639, 2016 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2015-6639.
60
[27] Z. Hua, J. Gu, Y. Xia, H. Chen, B. Zang, and H. Guan. vtz: Virtualizing ARM trustzone. In 26th
USENIX Security Symposium (USENIX Security 17), 2017.
[28] K. Ying, A. Ahlawat, B. Alsharifi, Y. Jiang, P. Thavai, and W. Du. Truz-droid: Integrating trustzone
with mobile operating system. In Proceedings of the 16th Annual International Conference on
Mobile Systems, Applications, and Services, 2018.
[29] J. Jang, C. Choi, J. Lee, N. Kwak, S. Lee, Y. Choi, and B. B. Kang. Privatezone: Providing a
private execution environment using arm trustzone. IEEE Transactions on Dependable and Secure
Computing, 2018.
[30] U. Kanonov and A. Wool. Secure Containers in Android: the Samsung KNOX Case Study, 2016.
[31] MITRE. CVE-2016-1919, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2016-1919.
[32] MITRE. CVE-2016-1920, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2016-1920.
[33] MITRE. CVE-2016-3996, 2017 (accessed December 21, 2019). https://nvd.nist.gov/vuln/
detail/CVE-2016-3996.
[34] F. Brasser, D. Gens, P. Jauernig, A. Sadeghi, and E. Stapf. Sanctuary: Arming trustzone with
user-space enclaves. In NDSS, 2019.
[35] A. Azab, K. Swidowski, R. Bhutkar, J. Ma, W. Shen, R. Wang, and P. Ning. Skee: A lightweight
secure kernel-level execution environment for arm. 2016.
[36] J. Martins, A. Tavares, M. Solieri, M. Bertogna, and S. Pinto. Bao: A lightweight static partitioning
hypervisor for modern multi-core embedded systems. In NG-RES@HiPEAC, 2020.
61
62