Hello everybody. I am back writing after a long break due to unexpected personal events followed by a busy period working on edKit and smart home. However here is the third article of this series on the GoogleCast protocol. This one will cover what I consider being the most intriguing part of the protocol : The receiver authentication.
The receiver authentication feature is very interesting because it shows how GoogleCast receivers are a key to the Google strategy on reaching the TV screen, and their will to keep it as closed as possible. This is the Mr Hyde side of the protocol. The Dr Jekyll part is the openness of GoogleCast : There are SDKs available for several development platforms (Android, iOS, and Chrome). However Mr Hyde is there when you go to the receiver part of GoogleCast : No trespassing, nothing to see here, you are not allowed to implement you own receiver. Only receiver devices manufactured by Google can be used.
This is enforced in the sender SDK, the SDK used in sender applications (on the mobile device). Once the sender has found a receiver device via MDNS (as explained in part 2 ), it sends a challenge to the receiver. If the receiver fails on this challenge, then the connection is closed. Otherwise, the communication can continue between the sender and the receiver devices. This is similar to a browser that checks the certificate of a web site, except that in this case there would be only one web site allowed.
Authentication Challenge
The authentication challenge is done through the TLS \"multiplexed\" socket, as explained in part 1. The authentication mechanism is shown in the following figure:
Two DeviceAuthMessage are exchanged. One for the challenge request, and one for the challenge answer. Both messages are in a namespace dedicated to device authentication: urn:x-cast:com.google.cast.tp.deviceauth. Their payload is in the payload_binary field of the CastMessage (see the protobuf declaration file for the complete structure of the messages)
So the sender first sends a DeviceAuthMessage message to the receiver. This is the challenge request. Its definition is the following one:
message DeviceAuthMessage {
// Request fields
optional AuthChallenge challenge = 1;
// Response fields
optional AuthResponse response = 2;
optional AuthError error = 3;
}
The challenge field can contain information on what kind of challenge the receiver must achieve. On the first Chromecast generation this field is empty, but if present it contains the following information:
message AuthChallenge {
optional SignatureAlgorithm signature_algorithm = 1
[default = RSASSA_PKCS1v15];
optional bytes sender_nonce = 2;
optional HashAlgorithm hash_algorithm = 3 [default = SHA1];
}
As time goes on, the protobuf definition file evolves, and new algorithms are added. As of writing this article there are 3 possible signature algorithms (unspecified, rsassa pkcs1 v1.5, and rsassa pss), and 2 possible hash algorithms (sha1 and sha256).
Then the receiver computes the challenge and answers by sending another DeviceAuthMessage with the response field being filled:
message AuthResponse {
required bytes signature = 1;
required bytes client_auth_certificate = 2;
repeated bytes intermediate_certificate = 3;
optional SignatureAlgorithm signature_algorithm = 4
[default = RSASSA_PKCS1v15];
optional bytes sender_nonce = 5;
optional HashAlgorithm hash_algorithm = 6 [default = SHA1];
optional bytes crl = 7;
}
The first generation Chromecast only fills the signature and client_auth_certificate fields. Let's see how they are computed.
Challenge Response
The response is computed as shown in the following diagram:
The Chromecast contains two certificate/key pairs. The first one is self-generated and is used for the TLS server. This certificate is only valid for 48 hours. The TLS cipher is ECDHE-RSA-AES128-GCM-SHA256.
The second pair is provisioned in the secure area of the Marvell chipset during manufacturing. This key/certificate pair is signed with the Eureka Gen1 certificate authority. Each Chromecast embeds its own key/certificate pair.
Completing the challenge consists in signing the SHA1 of the TLS certificate with the client private key. This signature is then put in the response.signature field of a DeviceAuthMessage. The response.client_auth_certificate field is filled with the client certificate (The one provisioned during manufacturing). Finally this DeviceAuthMessage is sent to the sender device as a response to the challenge.
Challenge Verification
On reception of the DeviceAuthMessage challenge response, the sender device checks the validity of the receiver device by checking two signatures:
First the sender checks that client_auth_certificate has been signed by the Eureka Gen1 certificate authority. This ensures that the receiver device is a legitimate GoogleCast receiver. Then it checks that the TLS certificate of the receiver has not expired, and that it is not valid beyond the next 48 hours. Finally it checks that the response.signature signature has been signed with the client_auth_certificate. These two last checks limit replay attacks from rogue receivers (one can replay a challenge only for 48hours). The challenge succeeds if all these tests pass. In such a case the receiver device is authenticated as a Google certified receiver and the communication can continue. Otherwise the connection is closed by the sender device.
Summary
This authentication algorithm was very carefully designed and implemented. When it was launched the Chromecast was surprisingly cheap, however its security was better than most of the IoT devices that are available today. It would be interesting to know if using a secure key for the client private key was a requirement of the product or just a benefit of using a chipset that supports DRM (Widevine is embedded). But anyway it is clear that nobody can implement a GoogleCast receiver without the agreement of Google (Breaking the PKI or using keys of some Chromecast devices is obviously not a solution).
That's all for now.