In this post we explore how the concepts discussed in our previous post are realized through Signal’s architectural elements, deployment, and other design principles. We will also see how key features, such as sending a message, work at run-time.
For identifying the different architectural views, we will use the 4+1 model described by Philippe Kruchten1.
Logical view The logical view of the system is important to identify functionality which the system provides to the user. Different diagrams are used to visualize the logical view of the system. These diagrams are useful to communicate new features in Signal.
Physical view The physical view contains the hardware aspect of the Signal application. There are two parts of hardware which are connected via an internet connection: the client (e.g. on a user’s phone), and the server (hosted by Signal Messenger LLC). It is important to understand how the hardware is connected to each other in order to understand why the software is architected in a certain way.
Development view It can be argued that the development view is crucial for any software system. Modularisation impacts how code is written and how well it can be maintained. This again impacts the ease at which features for Signal can be added, and how quickly issues can be fixed.
Process view The process view is important since non-functional requirements such as security and availability are crucial for a privacy centered instant messaging application. When the security is breached, or the up-time is low, users will resort to using a different application. Ease of use is another crucial requirement, as the co-founder Moxie Marlinspike said himself: “In many ways crypto was the easy part. The hard part is developing a product that people are actually going to use and want to use. That’s where most of our effort goes”2.
Scenarios This final view contains use cases which describe a sequence of interactions between objects and processes. Using these scenarios, architectural elements can be identified and Signal’s architectural design can be illustrated.
Non-functional but still important
Security One of the non-functional properties which Signal is well-known for, is security. The underlying security protocol, i.e. the Signal protocol, is cleared to use for the U.S. Senate3 and the NSA regards the encrypted voicecalls as a “major threat” to their operations4. Keeping the application secure during open source iterative development requires critical analysis of every proposed modification, since any contributor could potentially introduce weaknesses to the system.
Speed The signal protocol has also been developed to be fast. In order to decrease latency, Signal hosts more than a dozen servers around the globe2 to decrease the distance between the clients and a server.
Reliability Because Signal is also used for business critical communication, reliability is regarded to be an important property. Reliability of the code over time is achieved by following the deployment cycles that use beta testers to verify the workings of important aspects in the application. Since multiple servers are available, an outage of a server solely results in some extra latency, as another server can be used as a backup.
Transparency Convincing users of the trustworthiness of Signal is partially done using the open source initiative. The communication from developers to the users is another way to convey the intentions and guarantees that Signal offers.
Usability The Signal team has decided to keep the application as simple as can be for the end user. This in turn results in strict guidelines for keeping the user interface clean and withholding options from the user.
How is Signal deployed?
The Signal deployment process is as far as we know undisclosed. Nevertheless we can deduce the steps that have to be taken in order to release a new version.
For development of both the client and the server, Continuous Integration is used, but Continuous Deployment is not. Gradle is used to manage packages.
For the deployment view we will consider two parts of Signal: the Android client and the server. The client application runs on a user’s phone with Android 4.4 or newer5. The server application runs on a server owned by Signal Messenger LLC. The server and the client are connected via the internet.
Client The application receives updates via the Google Play Store. Depending on the user’s settings, it either updates automatically or asks for permission from the user to perform an update. Alternatively, the Signal website also hosts the compiled APK as a method to install the application.
Server Also hosted as an open source project, the server is developed to be hosted in a distributed manner. They run in SGX enclaves. These distributed enclaves can verify each other during operation using MRENCLAVE attestation checks6, again increasing the difficulty of compromising the server network. Signal also uses the AWS Global Accelerator in order to load balance server requests6.
Starting at the top: Architectural style and patterns
We will look at Signal from the highest level possible and then start zooming in on the architecture of the Android application and the design patterns that have been implemented in it.
Considering both Signal’s Android app and the servers that run its infrastructure, we can see that a client-server architecture has been deployed. When sending a message to a friend, the message is encrypted by the sending client, and then sent to the Signal servers. Consecutively, the server notifies the receiving client of a new message using Firebase Cloud Messaging. The receiving client then obtains the message from the Signal servers.
Zooming in on the Android app itself, it becomes evident that a layered architecture has been implemented by means of a model-view-controller (MVC) design pattern to separate the presentation and business layers. The Data Access Objects (DAOs) form the persistence layer which separates the business layer from the database layer. It has to be noted that not the whole Android app uses the MVC patterns, as traces of the model-view-viewmodel (MVVM) pattern are present throughout the source code.
To make the MVC pattern concrete, we will take the architecture of a single message in a conversation as an example. Such a message is represented by the
ConversationItem.java class and forms the View part of the MVC, together with a number of
xml files that describe the layout. The controller that controls the view is represented by the
ConversationFragment.java class. The final part of the MVC pattern is being fulfilled by the
MessageRecord.java class. This class represents the data in the application and simultaneously serves as a DAO to the local database within the application.
Diving deeper: Development of the application
In the previous section we have seen the architectural styles and design patterns that are used by Signal. By zooming in on the Android app, we discovered that underneath the app was a layered architecture. In this section, we will decompose the architecture of Signal into its main modules and see how the connectivity of the components reflects this layered architecture.
Deriving the high level decomposition of the module required a number of steps to bring the complexity of the obtained decomposition down. In the first step, folders from the Signal source code were grouped together by functionality in order to obtain the components of the app. In the figure above, these components have been depicted as blue rectangles. However, when analyzing the dependencies between said components, it became clear that they were too complex to be clearly represented by a single figure. In order to make the decomposition more readable, components with the same functionality have been grouped together into the main components that compose Signal, which have been depicted as the boxes with a title.
The decomposition of the main modules nicely shows the layered architecture that has been discussed before. We can see that the presentation layer is represented by the
UI component, which in turn gets its information from the business layer, represented by the
Conversation component. Up until this point, everything is in line with the architectural models. However, the decomposition as shown above does not make an explicit distinction between the persistence layer and the database layer. Instead, the
Storage main component (more specifically the
database component within this main component) does not only contain the code for the database layer, but it also contains the code that would normally be included in the persistence layer by offering the DAOs that have been described in the previous section.
Now that we have seen the layered architecture in its full glory, we will shortly consider the other components and give a quick description of their functions where deemed necessary. The
registration component serves the function of registering a user. The
lock component allows the user to set up a PIN code, which must be entered the next time a user tries to register with their phone number7. This places them somewhat out of the normal operation of Signal. The
communication component takes care of all communication, be it SMS, MMS or Firebase Cloud Messaging. The
services component contains different functionalities that are offered as services or jobs to run.
Looking at Signal during run time
We can also look at the application and how it operates during run time. Below we describe how a session is established in Signal, and how messages and calls between users are made.
Under the hood: sessions
To provide communication between two users, Signal creates a so-called session. Such a session contains the encryption keys used for communicating with another user. Since a user may have multiple devices, multiple sessions may be created: Suppose Alice and Bob want to be able to send messages: If Bob uses Signal on two devices (e.g. an Android Phone and a desktop computer), Alice has to establish a session to both of Bob’s devices. When a user removes the application or adds another device, Signal notifies his contacts in the chat that “the safety number has changed”. A user can verify the session by scanning a QR code on the other’s device.
You got mail
When sending a message to other users, the encryption keys from the sessions that are described above are used. The message is encrypted on the sender’s device for each active session with the recipient and sent to the Signal server. When the recipient opens the app, or the app checks for messages in the background, they will receive the encrypted message, which is stored on the recipient’s device(s). With their own decryption key, the recipient is now able to read the message.
Call me, maybe?
Signal also enables the user to call other users with audio or video. This uses a peer-to-peer (P2P) system. The request to start a call is sent from the user’s device to the server in an encrypted form, whereafter the recipient’s phone fetches this request, decrypts it locally and starts ringing. When the recipient accepts the call, an encrypted direct connection between the caller and the recipient is made, over which they communicate.
It is interesting to see how Signal is constructed. Not only does it have the functionality of a messaging application, but it also provides additional features to ensure user privacy and security. Its use of an MVC ensures Signal can decide to broaden its horizons, and develop new application as new platforms emerge. What’s more, if new security standards are adopted, Signal can update its library without affecting the app, to ensure privacy and security in the future.
Philippe Kruchten. Architectural Blueprints — The “4+1” View Model of Software Architecture. published in November 1995. retrieved from https://www.cs.ubc.ca/~gregor/teaching/papers/4+1view-architecture.pdf/. retrieved on 19-03-2020. ↩
Andy Greenberg. Your iPhone Can Finally Make Free, Encrypted Calls. published on 29-07-2014. retrieved from https://www.wired.com/2014/07/free-encrypted-calling-finally-comes-to-the-iphone/. retrieved on 17-03-2020. ↩ ↩2
Zack Whittaker. In encryption push, Senate staff can now use Signal for secure messaging. published on 16-05-2017. retrieved from https://www.zdnet.com/article/in-encryption-push-senate-approves-signal-for-encrypted-messaging/. retrieved on 17-03-2020. ↩
Michael W. Macleod-Ball, Gabe Rottman, Christopher Soghoian. The Civil Liberties Implications of Insecure Congressional Communications and the Need for Encryption. published on 22-09-2015. retrieved from https://www.aclu.org/sites/default/files/field_document/encrypt_congress_letter_final.pdf. retrieved on 18-03-2020. ↩
Signal support page. Installing Signal. retrieved from https://support.signal.org/hc/en-us/articles/360008216551-Installing-Signal. retrieved on 18-03-2020. ↩
Jim O’Leary. Improving Registration Lock with Secure Value Recovery. published on 27-01-2020. retrieved from https://signal.org/blog/improving-registration-lock/. retrieved on 19-03-2020. ↩