B.1. sip:phone Mobile App

B.1.1. Zero Config Launcher
B.1.1.1. 3rd Party Sign-Up Form
B.1.1.2. 3rd Party Launch Handler
B.1.2. Mobile Push Notification
B.1.2.1. Architecture
B.1.2.2. Configuring the Push Daemon

The sip:phone Mobile App is a mobile client for iOS and Android and supports voice calls via SIP, as well as presence and instant messaging via XMPP. The following chapters describe the steps needed to integrate it into the sip:carrier.

B.1.1. Zero Config Launcher

Part of the mobile apps is a mechanism to sign up to the service via a 3rd party web site, which is initiated on the login screen and rendered within the app. During the sign-up process, the 3rd party service is supposed to create a new account and/or subscriber on the sip:carrier (e.g. automatically via the API) and provide the end user with the access credentials.

In order to minimize the end customer steps to log in using these credentials (especially ruling out the need to manually enter them), the mobile apps come with a zero config mechanism, which allows to deliver the access credentials via a side channel (e.g. Email, SMS) and packed into a URL, which the user just has to click, and which automatically launches the app with the correct credentials. The following picture shows the overall work flow.

Figure B.1. Provisioning Push Workflow

Provisioning Push Workflow

There are two components provided by a 3rd party system, which are not part of the sip:carrier. One is the 3rd Party Sign-Up Form, and the other is the 3rd Party Launch Handler. The purpose of these components is to make the end customer to open a link with the access credentials via the sip:phone app.

B.1.1.1. 3rd Party Sign-Up Form

The 3rd Party Sign-Up Form is a web site the app shows to the end user when he taps the sign-up link on the Login Screen of the app. There, the end customer usually provides his contact details like name, address, phone number and/or email address etc. After validation, this web site creates the account and/or subscriber on the sip:carrier via the API.

After successfully creating the account and/or subscriber, this site needs to construct a specially crafted URL, which is sent back to the end customer via a side channel. Ideally, this channel would be SMS if you want to verify the end user’s mobile number, or an email if you want to verify her email address.

The sip:phone app registers a URL schema handler for URLs starting with sipphone://. If you start such a link, the app performs a Base64 decoding of the string right after the sipphone:// schema string, then decrypts the resulting binary string via AES using keys defined during the branding step. The resulting string is supposed to be

username=$user&server=$domain&password=$password.

Therefore, the 3rd Party Sign-Up Form needs to construct this string using the credentials defined while creating the subscriber via the sip:carrier API, then encrypt it via AES, and finally perform a Base64 encoding of the result.

[Note]

Up until and including version mr4.1.1 of the sip:carrier, the SIP login credentials are used here. Future versions will connect to the REST interface of the sip:carrier using the web credentials first and fetch the SIP credentials along with other settings from there.

An example code snipped in Perl to properly encode such a string is outlined here. The AES key and initialization vector ($key and $iv) are the standard values of the sip:phone app and should work, if you haven’t specified other values during the branding process.

#!/usr/bin/perl -w
use strict;
use Crypt::Rijndael;
use MIME::Base64;
use URI::Escape;

my $key = 'iBmTdavJ8joPW3HO';
my $iv = 'tww21lQe6cmywrp3';

my $plain = do { local $/; <> };
# pkcs#5 padding to 16 bytes blocksize
my $pad = 16 - (length $plain) % 16;
$plain .= pack('C', $pad) x $pad;

my $cipher = Crypt::Rijndael->new(
        $key,
        Crypt::Rijndael::MODE_CBC()
);
$cipher->set_iv($iv);
my $crypted = $cipher->encrypt($plain);
# store b64-encoded string and print to STDOUT
my $b64 = encode_base64($crypted, '');
print $b64, "\n";
# print to STDOUT using URL escaping also
print uri_escape($b64), "\n";

This snippet takes a string from STDIN, encrypts it via AES, encodes it via Base64 and prints the result on STDOUT. It also prints a second line with the same string, but this time URL escaped. To test it, you would run it as follows on a shell, granted it’s stored at /path/to/encrypt.pl.

echo -n 'username=testuser&server=example.org&password=testpass' \
  | /path/to/encrypt.pl

This command would result in the output strings CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI/Wv/VaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg== and CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI%2FWv%2FVaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg%3D%3D. The sip:phone can use the former string to automatically fill in the login form of the Login Screen if started via a Link like sipphone://CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI/Wv/VaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg==.

Here is the same code in PHP.

#!/usr/bin/php
<?php
$key = "iBmTdavJ8joPW3HO";
$iv = "tww21lQe6cmywrp3";

$clear = fgets(STDIN);
$cipher = fnEncrypt($clear, $key, $iv);

echo $cipher, "\n";
echo urlencode($cipher), "\n";

function fnEncrypt($clear, $key, $iv) {
        $pad = 16 - strlen($clear) % 16;
        $clear .= str_repeat(pack('C', $pad), $pad);
        return rtrim(base64_encode(mcrypt_encrypt(
                MCRYPT_RIJNDAEL_128, $key, $clear,
                MCRYPT_MODE_CBC, $iv)), "\0");
}
?>

Similar to the perl version, you can call it like this:

echo -n 'username=testuser&server=example.org&password=testpass' \
  | /path/to/encrypt.php

However, a URL with the sipphone:// schema is not displayed as a link in SMS or Email clients and thus can not be clicked by the end customer, so you need to make a detour via a normal http:// URL. To do so, you need a 3rd Party Launch Handler to trick the phone to open such a link.

This means that the 3rd Party Sign-Up Form needs to return a link with an URL pointing to the 3rd Party Launch Handler and pass the URL escaped string gathered above to the client via SMS or Email. Since it is a standard http:// link, it is click-able on the phone and can be launched from virtually any client (SMS, Email etc.) which properly renders an HTML link.

A possible SMS sent to the end customer (via the phone number entered in the sign-up from) could therefore look as follows (trying to stay below 140 chars).

http://example.org/p?c=CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI
%2FWv%2FVaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg%3D%3D to launch sipphone

An HTML Email could look like this:

Welcome to Example.org,
<a href="http://www.example.org/sipphone?c=CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI
%2FWv%2FVaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg%3D%3D">
click here
</a> to log in.

That way, you can on one hand verify the contact details of the user, and on the other hand send her the login credentials in a secure manner.

B.1.1.2. 3rd Party Launch Handler

The URL http://www.example.org/sipphone mentioned above can be any simple script, and its sole purpose is to send back a 301 Moved Permanently or 302 Moved Temporarily with a Location: sipphone://xxxxxxxxxxxx header to tell the phone to open this link via the sip:phone app. The xxxxxxxxxxxx is actually the plain (non-URL-escaped) string generated by the script above.

An example CGI script performing this task follows.

#!/usr/bin/perl -w
use strict;
use CGI;

my $q = CGI->new;
my $c = $q->param('c');
print CGI::redirect("sipphone://$c");

The script simply takes the URL parameter c from the URL http://www.example.org/sipphone?c=CI8VN8toaE40w8E4OH2rAuFj3Qev9QdLI%2FWv%2FVaBCVK2yNkBZjxE9eafXkkrQfmYdeu01PquS5P40zhUq8Mfjg%3D%3D crafted above and puts its content into a Location header using the sipphone:// schema, and finally sends a 301 Moved Permanently back to the phone.

The phone follows the redirect by opening the URL using the sip:phone app, which in turn decrypts the content and fills in the login form.

[Note]

Future versions of the sip:carrier will ship with this launch handler integrated in the system. Up until and including version mr4.1.1, this script needs to be installed on any webserver manually.

B.1.2. Mobile Push Notification

The sip:phone provides mobile push functionality to remotely start the app via the Google GCM or Apple APNS notification systems on inbound calls, in case the app is not registered.

[Caution]

Although stopping the App on the phone and letting it wake up via the push notification system safes some battery power on the phone, the whole push notification concept is a best effort framework for both iOS and Android provided by Apple and Google, respectively, and is therefore not 100% reliable.

B.1.2.1. Architecture

If the mobile push functionality is enabled, the call-flow looks as follows if there are no devices registered for a subscriber.

Figure B.2. Mobile Push Workflow

Mobile Push Workflow

  1. Caller sends INVITE to proxy
  2. Callee is offline, proxy forwards call to AS
  3. AS subscribes to registration state of callee at proxy
  4. AS plays early media to caller for feedback, as process might take a while
  5. AS sends push request to GCM/APNS service
  6. GCM/APNS service delivers request to callee
  7. Callee accepts request and confirms app start (unattended on Android), registers at proxy
  8. Proxy sends registration notification to AS
  9. AS deflects call back to proxy
  10. Proxy sends INVITE to callee
  11. Callee accepts call
  12. Response is sent back to caller, call setup completed

In case of a timeout (no registration notification within a certain time) at the application server, the call is rejected with an error.

B.1.2.2. Configuring the Push Daemon

The push daemon needs your specific keys and/or certificates obtained from Apple and Google, respectively.

Please read the official GCM Getting Started Guide for Android on how to obtain a push notification key from Google for GCM.

For instructions how to generate Apple push notification certificates and keys, please read the official Provisioning Procedures from Apple.

The final configuration in your /etc/ngcp-config/config.yml should look as follows.

pushd:
  apns:
    certificate: '/etc/ssl/private/your.phone.push.dev.pem'
    enable: 'yes'
    endpoint: gateway.push.apple.com
    feedback_endpoint: feedback.push.apple.com
    feedback_interval: 3600
    key: ''
    socket_timeout: 0
  enable: 'yes'
  gcm:
    enable: 'yes'
    key: 'xxxxxxxxxxxxxxxxxxxxxxxx-yyyyyyyyyyyyyy'
  port: 45060
  processes: 4
  ssl: 'yes'

Once configured, execute ngcpcfg apply to confirm your changes.