Firefox OS/Remote Control: Difference between revisions

→‎Architecture Designs: add disconnect and reconnection description
(→‎Control event processing: Add steps of control event processing)
(→‎Architecture Designs: add disconnect and reconnection description)
 
(37 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Introduction ==
== Introduction ==
Remote control is a new feature for Firefox OS on TV. We hope user can control TV at any device without installing any APP. Consider compatibility, remote control uses HTTP and AJAX as communication protocol between TV and user. User can easily connect to TV via open his/her browser, enter URL on TV and use the virtual touchpad to control TV just in seconds.
Remote control is a feature for Firefox OS on TV. After [https://addons.mozilla.org/en-US/android/addon/send-tab-to-tv/ Send tab to TV], user can easily extend browsing experience on TV via Firefox on Android, using virtual touchpad to control TV.


Meta Bug: {{Bug|1205939}}
Meta Bug: {{Bug|1205939}}
Line 13: Line 13:


== Architecture Designs ==
== Architecture Designs ==
* Remote Control Service: Entry point of remote control feature. Control service related logic and data in runtime.
* HTTP Server: Serves connections from user. Two types files can be served:
** Static file: Stored in Remote Control Client App, packaged in app://remote-control-client.gaiamobile.org
** Service script: Handle AJAX request and response for secure connection initialization, PIN code pairing and control event processing. Packaged in resource://gre/res/remotecontrol.
* Remote Control App: Provides service related user interface on TV. Communicate with Remote Control Service via MozSettings.


User interaction of remote control is divided into three parts:
[[File:RemoteControl BlockDiagram.png]]
# Establish secure connection
 
# PIN code pairing (optional, by user settings)
* [[Firefox_OS/Remote_Control_Service|Remote Control Service]]: Entry point of remote control feature. Control service related logic and data in runtime.
* TLS server: Serves connections from user.
 
User interaction of remote control is divided into two parts:
# Peer authentication
# Control event processing
# Control event processing


=== Establish secure connection ===
Any error occurs will close connection between server and client, reconnection is required. Server side error will sends message back to client to let user know what happen on Fennec.
Remote control is designed to protect data transmitted between client and server, for example: user input string may contains privacy data. Consider user scenario for remote control is in local network, TV is not able to get a unique name to provide HTTPS; remote control uses proprietary protocol to establish secure connection. Client is forced to exchange symmetric key (AES-GCM) with server in the first time. After key exchange, server uses UUID in cookie to identify client and key to decrypt messages. Following describes how keys are exchanged:
 
=== Peer authentication ===
Remote control is designed to protect data transmitted between client and server, for example: user input string may contains privacy data. The connection is based on self-signed TLS server. To prevent man in the middle(MITM) attack, we adopt [https://en.wikipedia.org/wiki/Password_Authenticated_Key_Exchange_by_Juggling J-PAKE] to exchange symmetric key for peer authentication. Following describes how it works:
 
[[File:RemoteControl_FirstTimeHandshake.png]]


# User opens the URL.
# The user sends the tab to TV on fennec.
# Client requests page without valid UUID.
# Client sends request to handshake without ID.
# Server response secure.html as requested page for key exchange.
# Server replies with the handshake type is 1st time handshake.
# Client acquires RSA public key from secure.sjs.
# Client computes J-PAKE round 1 and sends the result to server.
# Secure.sjs replies RSA public key SPKI in base64.
# Server generates PIN code and show on screen, computes J-PAKE round 1 and sends the result to client.
# Client imports RSA public key and wrap symmetric key.
# User enter PIN code, client computs J-PAKE round 2 with PIN code attached first 12 characters of server's TLS certificate fingerprint as weak secret.
# Client sends wrapped symmetric key to secure.sjs in base64.
# Client sends round 2 result to server.
# Secure.sjs replies a ticket number.
# Server computes J-PAKE round 2 with PIN code attached first 12 characters of server's TLS certificate fingerprint as weak secret.
# Secure.sjs unwraps symmetric key with RSA private key.
# Server dismisses PIN code notification on screen, sends round 2 result to client.
# Secure.sjs saves symmetric key.
# Both client and server compute J-PAKE final round, gets AES and HMAC key.
# Remote Control Service generates a new UUID, encrypted with symmetric key and binds encrypted UUID with ticket number.
# Server use two keys to get a signature of H(H(AES key)), then send the signature to client.
# Client polls encrypted UUID from secure.sjs by ticket number.
# Client verifies the signature matches it has.
# Client decrypts received UUID to double confirm server receives correct symmetric key.
# Client use two keys to get a signature of H(AES key), then send the signature to server.
# Client reloads the URL with UUID.
# Server verifies the signature matches it has.
# Server replies with the handshake finish with client's ID for connection in the future.


=== PIN code pairing ===
==== Re-authentication ====
PIN code is a mechanism to ensure the device connects to TV is physical near TV. While connects to TV, user needs to enter 4 digits PIN code on TV screen. After pass pairing, user is redirected to control page and not need to enter PIN code until: 1) 90 days, pairing expired or 2) user revokes all pairing in remote control app. Pairing can be turned off in remote control app. Following describes how PIN code pairing is done:
User is only required to input PIN code when first time connect to TV. In the second time, client and server leverage previous AES key value and derive new AES and HMAC key. This can reduce number of user input and make the procedure from send tab to TV to remote control more smoothly.


# User opens the URL.
[[File:RemoteControl SecondTimeHandshake.png]]
# Client requests page with UUID requires pairing.
# Server get the UUID and generate a PIN code.
# Remote control service sends PIN code to Gaia system app to trigger pairing notification on screen. (send chrome event)
# Server returns pairing.html as requested page for PIN code pairing.
# User enter PIN code on screen.
# Client encrypts PIN code.
# Client sends PIN code to pairing.sjs.
# Pairing.sjs replies a ticket number.
# Pairing.sjs decrypts PIN code using symmetric key received in establish secure connection.
# Pairing.sjs confirms PIN code correct from remote control service and delete pending PIN code.
# Pairing.sjs requests Gaia system app to dismiss pairing notification on screen. (send chrome event)
# Client queries PIN code pairing result from pairing.sjs by ticket number.
# Client reloads the URL with UUID.


After PIN code pairing, client reloads the URL with a valid UUID and get control page.
# The user sends the tab to TV on fennec.
# Client sends request to handshake with ID.
# Server looks up ID/AES key mapping and replies with the handshake type is 2nd time handshake.
# Client computes J-PAKE round 1 and sends the result to server.
# Server computes J-PAKE round 1 and sends the result to client.
# Client and server computes J-PAKE round 2 with first 4 characters of previous AES key value attached first 12 characters of server's TLS certificate fingerprint as weak secret.
# Client sends round 2 result to server.
# Server sends round 2 result to client.
# Both client and server compute J-PAKE final round, gets new AES and HMAC key.
# Server use two keys to get a signature of H(H(AES key)), then send the signature to client.
# Client verifies the signature matches it has.
# Client use two keys to get a signature of H(AES key), then send the signature to server.
# Server verifies the signature matches it has.
# Server replies with the handshake finish.
 
After authentication, client can sends control event to server.


=== Control event processing ===
=== Control event processing ===
Control page provides: 1) a virtual touchpad, 2) a virtual vertical scrollbar, 3) 3 function keys. Every touch, swipe or click will be generated to an event in JSON format, encrypted and send to TV. Following describes how control event is sent and processed:
Control page provides: 1) a virtual touchpad, 2) a virtual vertical scrollbar, 3) 3 function keys. Every touch, swipe or click will be generated to an event in JSON format then send to TV. Following describes how control event is sent and processed:
 
[[File:RemoteControl ControlEventProcessing.png]]


# User opens the URL.
# Client requests page with UUID can access control page.
# Server returns client.html as requested page for remote control.
# User operates control page.
# User operates control page.
# Client generates an event and encrypts the event using symmetric key.
# Client generates and sends the event in JSON format.
# Client sends encrypted event.
# Server parses the event to JSON object, dispatch to client.sjs.
# Client.sjs responses with latest event result.
# Client.sjs decrypts event with symmetric key received in establish secure connection.
# Client.sjs parses event and dispatch to Gecko or Gaia system app.
# Client.sjs parses event and dispatch to Gecko or Gaia system app.


=== Ajax Protocol ===
=== Data used in JPAKE authentication ===
==== Singer ID for JPAKE round 1 & 2: ====
* TV: server
* Fennec addon: client
 
==== Weak secret: ====
* TV: concatenate PIN and first 12 characters of TLS server cert SHA 256 fingerprint
* Fennec addon: concatenate user input PIN and first 12 characters connected TLS server cert SHA 256 fingerprint
 
==== HMAC Input for JAPKE final: ====
We use "AES_256_CBC-HMAC256", as aHkdfInfo, includes the full crypto spec, should be the same in both TV and fennec addon
 
==== Key confirmation: ====
 
Double hash of AES key:
## TV converts AES key to array buffer
## Sign AES key array buffer, get signature 1 (array buffer)
## Sign signature 1, get signature 2
## Convert signature 2 to base 64, send to Fennec addon
## Fennec addon do the same as TV from step 1 to 4
## Compare received base 64 string of self and TV's signature 2
 
Single hash of AES key:
## Fennec addon converts AES key to array buffer
## Sign AES key array buffer, get signature 1 (array buffer)
## Convert signature 1 to base 64, send to TV
## TV use HMAC key, received signature, AES key array buffer to verify if the signature is valid.
 
=== Authentication and Event Protocol ===
==== Request handshake ====
Request
  {
    type: 'auth'
    action: 'request_handshake'
    detail: {
      id: <id assigned by server, optional>
    }
  }
Response
  {
    type: 'auth'
    action: 'response_handshake'
    detail: 1 or 2, 1 for 1st handshake, 2 for 2nd handshake
  }
 
==== J-PAKE key exchange ====
Client send round 1
  {
    type: 'auth'
    action: 'jpake_client_1',
    detail: {
      gx1: gx1.value,
      gx2: gx2.value,
      zkp_x1: { gr: gv1.value, b: r1.value, id: 'client' },
      zkp_x2: { gr: gv2.value, b: r2.value, id: 'client' }
    }
  }
Server reply round 1
  {
    type: 'auth'
    action: 'jpake_server_1',
    detail: {
      gx1: gx1.value,
      gx2: gx2.value,
      zkp_x1: { gr: gv1.value, b: r1.value, id: 'server' },
      zkp_x2: { gr: gv2.value, b: r2.value, id: 'server' }
    }
  }
Client send round 2
  {
    type: 'auth'
    action: 'jpake_client_2',
    detail: {
      A: A.value,
      zkp_A: { gr: gvA.value, b: rA.value, id: 'client' }
    }
  }
Server reply round 2
  {
    type: 'auth'
    action: 'jpake_server_2',
    detail: {
      A: A.value,
      zkp_A: { gr: gvA.value, b: rA.value, id: 'server' }
    }
  }
 
==== Key confirmation ====
Server key confirmation
  {
    type: 'auth'
    action: 'server_key_confirm'
    detail: {
      signature: <double signature of AES key by HMAC key, in base64>
    }
  }
Client key confirmation
  {
    type: 'auth'
    action: 'client_key_confirmation'
    detail: {
      signature: <signature of AES key by HMAC key, in base64>
    }
  }
Server finish handshake
  {
    type: 'auth'
    action: 'finish_handshake'
    detail: {
      id: <id assigned by server, optional>
    }
  }


==== Touch Events ====
==== Touch Events ====


   {
   {
     type: 'touchstart',
     type: 'command'
    action: 'touchstart',
     detail: {
     detail: {
       width: <touch panel width, integer, in pixels>,
       width: <touch panel width, integer, in pixels>,
Line 89: Line 204:


   {
   {
     type: 'touchmove',
     type: 'command'
    action: 'touchmove',
     detail: {
     detail: {
       dx: <dx between current point and starting point, integer, in pixels>,
       dx: <dx between current point and starting point, integer, in pixels>,
Line 99: Line 215:


   {
   {
     type: 'touchend',
     type: 'command'
    action: 'touchend',
     detail: {
     detail: {
       dx: <same as "touchmove">,
       dx: <same as "touchmove">,
Line 116: Line 233:


   {
   {
     type: 'keypress',
     type: 'command'
    action: 'keypress',
     detail: <KeyEvent constant, string, sush as "DOM_VK_RETURN">
     detail: <KeyEvent constant, string, sush as "DOM_VK_RETURN">
   }
   }
Line 123: Line 241:


   {
   {
     type: 'input',
     type: 'command'
    action: 'textinput',
     detail: {
     detail: {
       clear: <whether to clear the entire string in the current focused input field, boolean>,
       clear: <whether to clear the entire string in the current focused input field, boolean>,
Line 131: Line 250:
   }
   }


==== Custom Events ====
==== Server reply error ====


   {
   {
     type: 'custom',
     type: common, or the event type sent from client
     action: <custom action name, string>,
     error: <error message of exception or root cause>
    ...
   }
   }
=== Pairing ===
Meta Bug: {{Bug|1207996}}
==== Flowchart ====
First Time Connection
[[File: RemoteControl FirstConnect.png]]
Enter PIN Code
[[File:RemoteControl EnterPIN.png]]
Resume Connection
[[File:RemoteControl ResumeConnection.png]]
Dismiss Pairing
[[File:RemoteControl DismissPairing.png]]
==== Protocol ====
from client to server via AJAX
  {
    pincode: <pincode>
  }
response when success
  {
    verified: true,
    uuid: <uuid>
  }
reponse when error
  {
    verified: false,
    reason: 'expired' / 'invalid'
  }
internal events at server side
  {
    type: 'mozChromeRemoteControlEvent',
    detail: {
      action: 'pin-created',
      pincode: <pincode>
    }
  }
  {
    type: 'mozChromeRemoteControlEvent',
    detail: {
      action: 'pin-destroyed'
    }
  }
  {
    type: 'mozContentEvent',
    detail: {
      type: 'remote-control-pin-dismissed',
      detail: {
        reason: 'timeout' / 'manually'
      }
    }
  }
=== Secure Connection ===
To protect private data between user and TV, we provide a secure connection which refers to SSL and [http://www.jcryption.org/ jCryption]. Here is the concept:
# Client requests RSA public key from TV.
# Client sends symmetric key and PIN code (if any) to TV, encrypted with public key.
# TV decrypts symmetric key with private key
# TV generates an UUID, encrypts with symmetric key then sends 2 UUIDs to client, one is encrypted the other is not.
# Client decrypts UUID with symmetric key, confirm UUID
# Begin remote control with symmetric key.
Goal of Remote Control is to create an easy to use way for every device, we hide public key exchange at the background. User doesn't need to input a long URL with public key nor scan QRCode. Everything is done automatically without interrupting user experience.
[[File: Remote_Security.png]]


== Bug Status ==
== Bug Status ==
133

edits