Security Tip: Protecting Session Sensitive Responses with Retrofit 2 and okhttp 3

Problem Statement:

A user could receive and view data that is not theirs, and we must prevent this from happening in a secure application.  Here is a diagram of how this could happen:

Flow Diagram of the Session Mismatch Issue

 

Implementation options with Retrofit 2 and okhttp 3:

Option 1:

Write a custom Retrofit 2 CallAdapter that blocks the response from being processed or passes an exception to the onFailure() method.

  • PROS:
    • Great if you use Retrofit 2 exclusively for session sensitive calls.
    • This can prevent the callback from being invoked, or you could call Retrofit 2’s onFailure() method.
  • CONS:
    • Retrofit 2 CallAdapter is complex and you have to write one for both plain Callbacks as well as for RxJava (if you are using both).
    • We’d have to copy the existing CallAdapter implementation in retrofit2.ExecutorCallAdapterFactory and modify it as it’s a final class.
    • This only works for Retrofit 2 calls, but not all networking calls made through okhttp 3.

Option 2:

When the client session is invalidated, use okhttp 3’s Dispatcher to cancel all running and queued calls.

  • PROS:
    • Very effective. All calls would immediately be cancelled.
  • CONS:
    • If there is a call like “Update Profile” that is still occurring, it would be cancelled, which is not desirable.
    • If there is an unauthenticated call happening, you’d have to ensure that was being executed on non session sensitive Retrofit 2 or okhttp 3 instance to avoid unwanted termination.

Option 3:

Same as the previous option, but instead occurs when a new client session is started, instead of when an old one ends.

  • PROS:
    • Very effective. All calls would immediately be cancelled.
  • CONS:
    • You would have to ensure this code got run before you kicked off any session sensitive calls, otherwise they would be immediately cancelled.
    • If there is an unauthenticated call happening in the background, you’d have to ensure that was being executed on non session sensitive Retrofit 2 or okhttp 3 instance to avoid unwanted termination.

Option 4:

Using an okhttp 3 Network Interceptor to return back an HTTP Response with a custom response code like 999 and removing the response body.

  • PROS:
    • Will work for:
      • All okhttp 3 calls.
      • Retrofit 2 Callback calls.
      • Retrofit 2 RxJava calls.
  • CONS:
    • It will appear like the HTTP response came back from the server so you will have to have custom logic in your response handler to check and see if this response has a HTTP status code of 999.
    • It feels a little “hacky”… but would prevent the security hole.

Option 5: (My Choice)

Using an okhttp 3 Network Interceptor to throw a custom SessionMismatchException when this problem is detected, and handle the Exception appropriately.

  • PROS:
    • Will work for:
      • All okhttp 3 calls
      • Retrofit 2 Callback Calls
      • Retrofit 2 RxJava Calls
    • This is truly an “Exception” scenario, so this makes sense.
    • The request is executed fully, but will not be received by the client. (This could be a “con” depending on your use case)
  • CONS:
    • You must code your onFailure and onError handlers to appropriately handle this SessionMismatchException type.
    • If you just extend IOException, okhttp 3 will by default retry the HTTP call.  However, if you extend java.net.SocketTimeoutException, okhttp 3 will not retry.

My Choice: Option 5, throwing a custom SessionMismatchException.  This seemed to be the most flexible and intuitive since this truly is an Exception/Failure case.  I’ve provided a sample implementation of this below.

Assumption: You have a  “SessionManager” in your Android code which is aware of the current session.

Let me know if this was helpful, or if you’d do something different on Twitter at @HandstandSam

Controlling the Android Emulator and Virtual Devices (AVDs) via the command-line

I Googled all around to try and figure out how to tweak Android Emulator virtual devices (AVDs) via the command-line.  The Android Emulator documentation online has some options for running the emulator, but it didn’t allow me to specify memory at runtime, and many other things I wanted to customize.  There is also documentation specific to the creation of AVDs (vs just the running of them on the emulator), but that kept referring to the UI tools for it. I’ve gotten so used to Googling for help, that I didn’t think of running help locally :-p

emulator -help

That gives us a LOT of options that are not documented on the website including.

Android Emulator usage: emulator [options] [-qemu args]
  options:
    -list-avds                     list available AVDs
    -sysdir <dir>                  search for system disk images in <dir>
    -system <file>                 read initial system image from <file>
    -writable-system               make system image writable after 'adb remount'
    -datadir <dir>                 write user data into <dir>
    -kernel <file>                 use specific emulated kernel
    -ramdisk <file>                ramdisk image (default <system>/ramdisk.img
    -image <file>                  obsolete, use -system <file> instead
    -initdata <file>               same as '-init-data <file>'
    -data <file>                   data image (default <datadir>/userdata-qemu.img
    -partition-size <size>         system/data partition size in MBs
    -cache <file>                  cache partition image (default is temporary file)
    -cache-size <size>             cache partition size in MBs
    -no-cache                      disable the cache partition
    -nocache                       same as -no-cache
    -sdcard <file>                 SD card image (default <system>/sdcard.img
    -snapstorage <file>            file that contains all state snapshots (default <datadir>/snapshots.img)
    -no-snapstorage                do not mount a snapshot storage file (this disables all snapshot functionality)
    -snapshot <name>               name of snapshot within storage file for auto-start and auto-save (default 'default-boot')
    -no-snapshot                   perform a full boot and do not do not auto-save, but qemu vmload and vmsave operate on snapstorage
    -no-snapshot-save              do not auto-save to snapshot on exit: abandon changed state
    -no-snapshot-load              do not auto-start from snapshot: perform a full boot
    -snapshot-list                 show a list of available snapshots
    -no-snapshot-update-time       do not do try to correct snapshot time on restore
    -wipe-data                     reset the user data image (copy it from initdata)
    -avd <name>                    use a specific android virtual device
    -skindir <dir>                 search skins in <dir> (default <system>/skins)
    -skin <name>                   select a given skin
    -no-skin                       don't use any emulator skin
    -noskin                        same as -no-skin
    -dynamic-skin                  dynamically construct a skin of given size, requires -skin WxH option
    -memory <size>                 physical RAM size in MBs
    -accel <mode>                  Configure emulation acceleration
    -no-accel                      Same as '-accel off'
    -ranchu                        Use new emulator backend instead of the classic one
    -engine <engine>               Select engine. auto|classic|qemu2
    -netspeed <speed>              maximum network download/upload speeds
    -netdelay <delay>              network latency emulation
    -netfast                       disable network shaping
    -code-profile <name>           enable code profiling
    -show-kernel                   display kernel messages
    -shell                         enable root shell on current terminal
    -no-jni                        disable JNI checks in the Dalvik runtime
    -nojni                         same as -no-jni
    -logcat <tags>                 enable logcat output with given tags
    -no-audio                      disable audio support
    -noaudio                       same as -no-audio
    -audio <backend>               use specific audio backend
    -raw-keys                      disable Unicode keyboard reverse-mapping
    -radio <device>                redirect radio modem interface to character device
    -port <port>                   TCP port that will be used for the console
    -ports <consoleport>,<adbport> TCP ports used for the console and adb bridge
    -onion <image>                 use overlay PNG image over screen
    -onion-alpha <%age>            specify onion-skin translucency
    -onion-rotation 0|1|2|3        specify onion-skin rotation
    -dpi-device <dpi>              specify device's resolution in dpi (default 165)
    -scale <scale>                 scale emulator window (deprecated)
    -http-proxy <proxy>            make TCP connections through a HTTP/HTTPS proxy
    -timezone <timezone>           use this timezone instead of the host's default
    -dns-server <servers>          use this DNS server(s) in the emulated system
    -cpu-delay <cpudelay>          throttle CPU emulation
    -no-boot-anim                  disable animation for faster boot
    -no-window                     disable graphical window display
    -version                       display emulator version number
    -report-console <socket>       report console port to remote socket
    -gps <device>                  redirect NMEA GPS to character device
    -keyset <name>                 specify keyset file name
    -shell-serial <device>         specific character device for root shell
    -tcpdump <file>                capture network packets to file
    -bootchart <timeout>           enable bootcharting
    -charmap <file>                use specific key character map
    -prop <name>=<value>           set system property on boot
    -shared-net-id <number>        join the shared network, using IP address 10.1.2.<number>
    -nand-limits <nlimits>         enforce NAND/Flash read/write thresholds
    -gpu <mode>                    set hardware OpenGLES emulation mode
    -camera-back <mode>            set emulation mode for a camera facing back
    -camera-front <mode>           set emulation mode for a camera facing front
    -webcam-list                   lists web cameras available for emulation
    -screen <mode>                 set emulated screen mode
    -force-32bit                   always use 32-bit emulator
    -selinux <disabled|permissive> Set SELinux to either disabled or permissive mode

     -qemu args...                 pass arguments to qemu
     -qemu -h                      display qemu help

     -verbose                      same as '-debug-init'
     -debug <tags>                 enable/disable debug messages
     -debug-<tag>                  enable specific debug messages
     -debug-no-<tag>               disable specific debug messages

     -help                         print this help
     -help-<option>                print option-specific help

     -help-disk-images             about disk images
     -help-keys                    supported key bindings
     -help-debug-tags              debug tags for -debug <tags>
     -help-char-devices            character <device> specification
     -help-environment             environment variables
     -help-keyset-file             key bindings configuration file
     -help-virtual-device          virtual device management
     -help-sdk-images              about disk images when using the SDK
     -help-build-images            about disk images when building Android
     -help-all                     prints all help content

I hope you found this from YOUR Google search about this, and it helped 🙂

Running Multiple Android Emulators Simultaneously on OSX

I had a long standing issue where I could only launch two emulators on my Macbook Pro simultaneously.  Any other emulators would launch and get a black screen and wouldn’t load.  I accepted this as fact, and carried on with life.

screen-shot-2016-09-07-at-7-11-45-pm

Finally today I found the need to figure out “why” this was the case as I wanted to start sharding my Android UI tests to speed them up.  I was given the suggestion that it could be the # of CPUs or the amount of RAM.  If you look in the logs you may see something like this (if you launch the emulator from android avd):

screen-shot-2016-09-07-at-7-15-46-pm

or you may see:

“HAXM does not have enough memory remaining to load this AVD.”

In order to change your memory allocation for HAXM, you need to re-install it, so run the installer again which is a DMG at: [$ANDROID_HOME/sdk/extras/intel/Hardware_Accelerated_Execution_Manager/ ] and this time select more memory. [HAXM Technical Docs]screen-shot-2016-09-07-at-8-27-05-pm

But… before you install, make sure you have the latest version. The latest version as of September 7th, 2016 is 6.0.3 (Which was released on June 21, 2016).
screen-shot-2016-09-07-at-7-33-01-pm

On my Macbook, I was given 2048MB of memory by default which allowed me to run 2 emulators simultaneously (as seen above).screen-shot-2016-09-07-at-6-58-46-pm

I have 16GB total memory though, so lets make it so I can run a bunch of emulators at once by allocating 8GB 🙂
8192
confirm

Here is my Macbook Pro running 6 Android emulators simultaneously after the changes:
screen-shot-2016-09-07-at-8-17-17-pm

Success!!!  May the sharding begin!

Related Links:

Lots of Upcoming Speaking Engagements!

I’m excited to announce I’ve been accepted to talk at a bunch of upcoming events.


Espresso: A Screenshot is Worth 1,000 Words

Do your product owners, designers and the people that pay you understand what in the world your Espresso tests are doing and why they are valuable? You’ve spent so much time and effort writing these tests and your whole team deserves to get the most benefit out of them. In this talk you’ll learn how to setup your Espresso tests to take programatic screenshots, and leverage the Robot pattern of testing for clean, readable, and maintainable tests. You’ll also learn guidelines on when it’s appropriate to write Espresso tests instead of Robolectric or Unit tests, and how to leverage mock data to make your Espresso tests run with Tesla-like speed.

I have architected the Espresso test setup for our Capital One Wallet Android team and helped execute our ongoing continuous integration efforts. We’ve seen a 4x+ speed improvement over Appium, have more maintainable tests, and now have visibility for anyone to look into our test coverage.


“Continuous Integration Tips & Tricks for Android”
This is a co-talk with Dan Jarvis, the tech lead for Capital One Wallet for Android.

DNS on the Android Emulator

The last few days I have been struggling to get the Android Emulator to connect to certain domains through a proxy we have at my job.  Because of this, I started messing with my OS X DNS configuration and got myself in a DNS mess.  I finally figured my way out, so I wanted to share with you how DNS works with the Android Emulator, and hopefully avoid the troubles I ran into.

Android Documentation:

Screen Shot 2016-05-03 at 7.44.53 PM
http://developer.android.com/tools/help/emulator.html#dns

The Android Emulator uses the DNS settings of your OS X machine from/etc/resolv.conf as mentioned above.  The file looks something like:

#
# Mac OS X Notice
#
# This file is not used by the host name and address resolution
# or the DNS query routing mechanisms used by most processes on
# this Mac OS X system.
#
# This file is automatically generated.
#
search fios-router.home
nameserver 192.168.1.1

This file is re-generated by OS X as you connect to different networks (different WiFi hotspots or ethernet connections) to properly resolve DNS entries while connected to that network.

The thing I didn’t know is that /etc/resolv.conf is by default a symbolic link to /var/run/resolv.conf.  So, if you ever mess with /etc/resolv.conf and want to put back the original, you’ll have to re-create the symbolic link on your system, so that your global overrides are no longer in place.  Create the symbolic link using the following command:

sudo ln -s /var/run/resolv.conf /etc/resolv.conf

Anyways, you can override your DNS entries for the Android Emulator via the command line using the “-dns-server” option, or you can edit /etc/resolv.conf and override it globally.  Just realize that you need to create a symbolic link to /var/run/resolv.conf in order to “revert” changes if you mess with /etc/resolv.conf.

Happy DNS’ing with the Android Emulator and I hope for your case you don’t ever have to deal with it!

Using the Android Emulator for Continuous Integration

Screen Shot 2016-04-23 at 9.06.54 PM

I spent the last few weeks figuring out how to get our Android Tests running on our Jenkins CI (Continuous Integration) server using the latest Android Emulator. I am sharing what I learned so that I can hopefully help someone else and so I can refer back to it in the future.

Result of this tutorial/example:

You will be able to programmatically create an Android Emulator AVD (Android Virtual Device), start it, wait for it to load, run your tests, then kill the emulator, generate a Spoon html test report.

Screen Shot 2016-04-23 at 8.55.17 PM

Assumptions for this example:

  • You have the Android SDK configured on this machine with:
    • SDK components for API 23
    • The latest build tools
    • Google apis support
    • API 23, x86_64 with Google APIs Image
    • HAXM support installed
  • You have an Android build flavor named “qa”.
  • You are running your tests on a “debug” build.
  • You have built the APK and test APK with:
    • ./gradlew clean app:assembleQaDebug and app:assembleQaDebugAndroidTest
  • You have Android tests in a Java package called “integration_tests”
  • spoon-runner-1.2.0-jar-with-dependencies.jar exists in your working directory.
  • You want to use an API 23, x86_64, Google APIs enabled AVD (Note, you could easily change these, but this is what this example uses)

To download all the necessary SDK components referenced above, you can run the following command, or just download the components using the UI version of the Android SDK Manager.  NOTE: These commands aren’t scripted for a CI server.  You have to manually accept licensing terms:

android update sdk --no-ui --all --filter 'platform-tools,extra-android-support,build-tools-21.1.1,extra-android-m2repository,extra-google-m2repository,android-23,addon-google_apis-google-23,sys-img-x86_64-google_apis-23'

This Android test execution script will:

  • Forcefully create an AVD for this test (so that it is a fresh device every time)
  • Use port 6000 for the emulator (This is arbitrary, but by default, it is 5554 and assigned by Android).
  • Start the emulator for the AVD on a specific port (so we can target the device by serial with “emulator-{PORT}”
  • Ensure the emulator started by polling for the emulator to be booted
  • Use Spoon to run the tests in a specific package
  • Kill this emulator instance after our tests complete
#CONFIG
FLAVOR="qa"
PACKAGE_NAME="com.example.myapp"
AVD_NAME="integration-tests"
PORT=6000

##############################################################################

#Ensure the Test APK is built already.
TEST_APK_FILE="app/build/outputs/apk/app-${FLAVOR}-debug-androidTest-unaligned.apk"
if [ ! -f "${TEST_APK_FILE}" ]
then
	echo "androidTest APK doesn't exist, exiting.  Make sure you run ./gradlew app:assembleQaDebug app:assembleQaDebugAndroidTest"
exit
else
	echo "androidTest APK Exists, continuing"
fi

#Calculate the Serial Number of the emulator instance
SERIAL=emulator-${PORT}

echo "Creating (forceful) AVD with name ${AVD_NAME}"
# We have to echo "no" because it will ask us if we want to use a custom hardware profile, and we don't.
echo "no" | android create avd \
    --name "${AVD_NAME}" \
    --target "android-23" \
    --abi "google_apis/x86_64" \
    --skin "WXGA720" \
	--force
echo "AVD ${AVD_NAME} created."

#Start the Android Emulator
#"2>&1" combines stderr and stdout into the stdout stream
START_EMULATOR="emulator \
	-avd ${AVD_NAME} \
	-netspeed full \
	-gpu on \
	-netdelay none \
	-port ${PORT}"

echo $START_EMULATOR
$START_EMULATOR 2>&1 &

#Ensure Android Emulator has booted successfully before continuing
EMU_BOOTED='unknown'
while [[ ${EMU_BOOTED} != *"stopped"* ]]; do
    sleep 5
    EMU_BOOTED=`adb -s ${SERIAL} shell getprop init.svc.bootanim || echo unknown`
done

duration=$(( SECONDS - start ))
echo "Android Emulator started after $duration seconds."

# Get the file name of the QA APK (we need to cope with the version number changing)
APK_LIST_AS_TEXT="$(ls -t app/build/outputs/apk/*-android-debug-*-${FLAVOR}.apk)"
APK_FILES=( $APK_LIST_AS_TEXT )

# Use the Spoon utility as a test runner
SPOON_COMMAND="java -jar spoon-runner-1.2.0-jar-with-dependencies.jar \
	-serial ${SERIAL} \
	--apk ${APK_FILES[0]} \
	--test-apk ${TEST_APK_FILE} \
	--no-animations \
	--fail-on-failure \
	--debug
echo "Running: ${SPOON_COMMAND}"
${SPOON_COMMAND}

#Stop the Android Emulator
echo "Killing the Android Emulator with serial: ${SERIAL}"
adb -s ${SERIAL} emu kill

Final notes & tips:

  • Because the Android Emulator’s serial number is in the format of “emulator-{SERIAL}”, it is very important to start the emulator on a specific port (using the “-port {PORT}” param) so that you can reference the image by serial number.  This allows you to launch more than one emulator on the same build machine.
  • Command to list available Android platforms
    android list targets
  • Command to list available AVDs
    android list avd
  • Command to list all available SDK components that you can –filter for in the “update sdk” command:
    android list sdk --all --extended

If you have any questions or comments, let me know on Twitter at @HandstandSam.

Running WireMock on Android

Update: (September 17th, 2017) – WireMock 2.8.0 is the latest working version on Android at this point in time.  Check out https://github.com/handstandsam/AndroidHttpMockingExamples and https://github.com/handstandsam/ShoppingApp for the latest examples as this blog post was written in January of 2016.


WireMock on Android is now possible!  Thanks to work by @tomakehurst with the 2.0-beta branch of WireMock to revamp the dependency structure from the 1.0 branch, and a tiny change I put in to match Android’s HttpClient method signatures, it can now run on Android without any modifications.

WireMock includes the following features out of the box which are very valuable in a wide variety of development and testing scenarios:

  • HTTP response stubbing, matchable on URL, header and body content patterns
  • Request verification
  • Runs in unit tests, as a standalone process or as a WAR app
  • Configurable via a fluent Java API, JSON files and JSON over HTTP
  • Record/playback of stubs
  • Fault injection
  • Per-request conditional proxying
  • Browser proxying for request inspection and replacement
  • Stateful behaviour simulation
  • Configurable response delays

It’s true you don’t have to put WireMock on your Android device to use it.  You can also just run WireMock on a computer and get a lot of benefit out of this by pointing your HTTP calls to your computer.  This can be very useful during development and testing, but will require you to manage these mock files separate from your Android application. When you run WireMock on your computer, you’re creating a configuration dependency which is challenging to maintain for scripted testing scenarios.  By including WireMock in your Android project and starting the server programmatically, you are able to remove the dependency of having to run an external server.

Here are your build.gradle dependencies to bundle WireMock 2.0.8-beta into your Android project:

compile("com.github.tomakehurst:wiremock:2.0.8-beta") {
    //Allows us to use the Android version of Apache httpclient instead
    exclude group: 'org.apache.httpcomponents', module: 'httpclient'

    //Resolves the Duplicate Class Exception
    //duplicate entry: org/objectweb/asm/AnnotationVisitor.class
    exclude group: 'asm', module: 'asm'

    //Fixes Warning conflict with Android's version of org.json
    //org.json:json:20090211 is ignored for debugAndroidTest as it may be conflicting with the internal version provided by Android.
    exclude group: 'org.json', module: 'json'
}
//Android compatible version of Apache httpclient.
compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1'

If you want an example of what it looks like to use a bundled WireMock instance in an Android test, check out an examples repository on GitHub I put together to show this.

Here is an Espresso Test from the examples project:

@RunWith(AndroidJUnit4.class)
public class WireMockActivityInstrumentationTestCase2 extends ActivityInstrumentationTestCase2 {
    private MainActivity activity;

    public WireMockActivityInstrumentationTestCase2() {
        super(MainActivity.class);
    }

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(BuildConfig.PORT);

    @Before
    @Override
    public void setUp() throws Exception {
        super.setUp();
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        activity = getActivity();
    }
    @Test
    public void testWiremock() {
        String jsonBody = asset(activity, "atlanta-conditions.json");
        stubFor(get(urlMatching("/api/.*"))
                .willReturn(aResponse()
                        .withStatus(200)
                        .withBody(jsonBody)));

        String serviceEndpoint = "http://127.0.0.1:" + BuildConfig.PORT;
        activity.setWeatherServiceManager(new WeatherServiceManager(serviceEndpoint));

        onView(ViewMatchers.withId(R.id.editText)).perform(typeText("atlanta"));
        onView(withId(R.id.button)).perform(click());
        onView(withId(R.id.textView)).check(matches(withText(containsString("GA"))));
    }
}

Full Source File on GitHub

If you’re using WireMock for only testing or mock scenarios, you can justify the dependency overhead of including the library because of it’s vast array of features.  But, I wouldn’t suggest embedding it into your normal app as it has a very large method count and size footprint.  Here’s a breakdown of how big WireMock and it’s dependencies are:

Screen Shot 2016-01-30 at 8.23.55 PM
Source: http://www.methodscount.com/?lib=com.github.tomakehurst:wiremock:2.0.8-beta

That puts us at a total of 54,691 methods if you include WireMock 2.0.8-beta in your project by itself. Wowsa, that’s a lot, especially with Android’s 65,000 Method Limit (which can be circumvented using a technique called MultiDex).

Dependency exclusions & inclusions for WireMock to run on Android:

  • Exclude: org.apache.httpcomponents:httpclient (-4,098 Methods)
  • Exclude: org.json:json (-357 Methods)
  • Exclude: asm:asm (-391 Methods)
  • Include: org.apache.httpcomponents:httpclient-android (+3,389 Methods)

Grand Total Method Count for Android: 53,234

Grade dependencies tree for WireMock 2.0.8-beta:

+--- com.github.tomakehurst:wiremock:2.0.8-beta
|    +--- org.eclipse.jetty:jetty-server:9.2.13.v20150730
|    |    +--- javax.servlet:javax.servlet-api:3.1.0
|    |    +--- org.eclipse.jetty:jetty-http:9.2.13.v20150730
|    |    |    \--- org.eclipse.jetty:jetty-util:9.2.13.v20150730
|    |    \--- org.eclipse.jetty:jetty-io:9.2.13.v20150730
|    |         \--- org.eclipse.jetty:jetty-util:9.2.13.v20150730
|    +--- org.eclipse.jetty:jetty-servlet:9.2.13.v20150730
|    |    \--- org.eclipse.jetty:jetty-security:9.2.13.v20150730
|    |         \--- org.eclipse.jetty:jetty-server:9.2.13.v20150730 (*)
|    +--- org.eclipse.jetty:jetty-servlets:9.2.13.v20150730
|    |    +--- org.eclipse.jetty:jetty-continuation:9.2.13.v20150730
|    |    +--- org.eclipse.jetty:jetty-http:9.2.13.v20150730 (*)
|    |    +--- org.eclipse.jetty:jetty-util:9.2.13.v20150730
|    |    \--- org.eclipse.jetty:jetty-io:9.2.13.v20150730 (*)
|    +--- org.eclipse.jetty:jetty-webapp:9.2.13.v20150730
|    |    +--- org.eclipse.jetty:jetty-xml:9.2.13.v20150730
|    |    |    \--- org.eclipse.jetty:jetty-util:9.2.13.v20150730
|    |    \--- org.eclipse.jetty:jetty-servlet:9.2.13.v20150730 (*)
|    +--- com.google.guava:guava:18.0
|    +--- com.fasterxml.jackson.core:jackson-core:2.6.1
|    +--- com.fasterxml.jackson.core:jackson-annotations:2.6.1
|    +--- com.fasterxml.jackson.core:jackson-databind:2.6.1
|    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.6.0 -> 2.6.1
|    |    \--- com.fasterxml.jackson.core:jackson-core:2.6.1
|    +--- org.skyscreamer:jsonassert:1.2.3
|    +--- xmlunit:xmlunit:1.6
|    +--- com.jayway.jsonpath:json-path:2.0.0
|    |    +--- org.slf4j:slf4j-api:1.7.10 -> 1.7.12
|    |    \--- net.minidev:json-smart:2.1.1
|    |         \--- net.minidev:asm:1.0.2
|    +--- org.slf4j:slf4j-api:1.7.12
|    +--- net.sf.jopt-simple:jopt-simple:4.9
|    \--- junit:junit:4.12 (*)
\--- org.apache.httpcomponents:httpclient-android:4.3.5.1

My recommendation: If you need the features WireMock provides, go with it.  It’s sexy and it works well.  WireMock has a lot of bang for the buck, and you’re only taking this overhead in test and mock build flavors.  If you’re looking for something WAY more basic on Android, try okhttp’s MockWebServer project.  It does allow you to run an HTTP server within your app but it’s very limited and that makes it lightweight.  You can queue up responses in a row, or create a custom “dispatcher” which allows you to choose which response to send back based on a request.  It really depends on your use cases as to which one you choose.  There is also an example of MockWebServer being used in the same AndroidHttpMockingExamples project on GitHub.  Note: the examples are there mostly for configuration but don’t exercise all of WireMock’s features.  In this examples project, you will see that MockWebServer is an equally viable solution because of the simplicity of this use case.

The latest version of okhttp’s MockWebServer has 20,453 methods, but that includes okhttp and junit which you are probably already using in your project.  The biggest culprit is BouncyCastle (a java implementation of many encryption algorithms) which has 15,163 on it’s own.

Screen Shot 2016-01-30 at 9.54.32 PM

Source: http://www.methodscount.com/?lib=com.squareup.okhttp3:mockwebserver:3.0.1

Gradle Dependencies for okhttp’s MockWebServer:

\--- com.squareup.okhttp3:mockwebserver:3.0.1
     +--- com.squareup.okhttp3:okhttp:3.0.1
     |    \--- com.squareup.okio:okio:1.6.0
     +--- com.squareup.okhttp3:okhttp-ws:3.0.1
     |    \--- com.squareup.okhttp3:okhttp:3.0.1 (*)
     +--- org.bouncycastle:bcprov-jdk15on:1.50
     \--- junit:junit:4.11 -> 4.12 (*)

Related Info: If you just want a little more info and more advanced use cases about how to use WireMock on Android using Espresso UI tests, Michael Bailey has a great talk up on YouTube from 2014.  He talks about how he used an embedded WireMock instance on Android that he hacked together for version 1 of WireMock (library is not publicly available).  He shows some really good examples and I highly recommend watching the talk.

Finally: One thing I haven’t figured out how to do on Android yet is to use the “__files” and “mappings” directories the same way you can on a computer.  If anyone knows how to get this to work, or a nice work-around, please let me know.

Are you using WireMock on Android?  If so, please let me know on Twitter by tweeting @HandstandSam, I’d love to know.

Determining Supported Processor Types (ABIs) for an Android Device

This article is a quick overview on the types of Android processor instruction set types, known as an ABI (Application Binary Interface) and how to determine which ones your device supports.

In order to include any compiled native C libraries, such as “mylib.so” into your Android application, it needs to be compiled it for a specific ABI.

ABIs found on Android are in 3 categories:

  • ARM
    • armeabi
    • armeabi-v7a (Typically also supports armeabi)
    • arm64-v8a (Typically also supports armeabi and armeabi-v7a)
  • X86
    • x86
    • x86_64 (Typically also supports x86)
  • MIPS
    • mips
    • mips64 (Typically also supports mips)

When including native libraries into your app, you’ll typically see them packaged within an AAR dependency, but sometimes you will have to add them manually.  When you have to add them manually you will have to structure your dependencies to tell which ABI the code is compiled for.

For example:

  • app/libs/armeabi/mylib.so or
  • app/libs/x86/mylib.so

“armeabi-v7a” is BY FAR the most widely seen ABI on Android. About 90+% of all phones made in the last few years supports this.  x86 is only on a few devices including the The Asus Zenphone 2, Genymotion Emulator and some Android Emulator images.   I’ve never even heard of any modern android device using a “mips” based processor.

To figure out what type of ABI your Android device has, you have two methods.  You can do it with an ADB (Android Debug Bridge) command, or programmatically through code.

Related Links:

Android HTTPS Cert Pinning (Part 1) – Obtaining CA Certificates and Public SSL Key

What is certificate pinning?

Ensures a client is connecting over HTTPS to the intended server ONLY and no other.  This is achieved by including public server certificate information on the client and not relying on the device’s trust store (such as the one on Android or the JVM).

This trust store can be augmented by adding in additional Certificate Authority (CA) Certs and then HTTPs traffic can still be monitored.  A common development use of monitoring HTTPS traffic is using Charles Proxy.

Obtaining A Server’s Public SSL Key

openssl s_client -connect www.google.com:443 | openssl x509 -pubkey -noout

depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhtxFolwNJBGuhYRGDiNF
2Av9jTt0c2vk5mLBrO9td2hFyvw0B0fPpxbkOm72Cd4OnGVXxIB0hp1XRWXuyP+p
FMHmXSshVWDIrcAwjR5r+WnAqrLacZJNHkDOWO+COY8CUHGTn9YfwKwuHQROp6aH
Yu7YhppMXu3dL1kZ55AzYdwgYVc6BdxmDsGWRZbgZ0qt/QQC0zmbR+hLpZAKhHmN
VnBRXYz5q+XLEBmjQnwVmwMzPCvZFzNEWan0wQsCRqcJ19lO5hLxn4O2T718qF2h
cd1sH1RL6HlhUxJe09L3yoGCMoENIq6ywIrVgFsZtyhg8TMyCZuRtyCS+ux9ma0A
7wIDAQAB
-----END PUBLIC KEY-----

Decoding a Certificate

openssl s_client -connect www.google.com:443 | openssl x509 -text

depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:30:5c:d0:43:91:9d:86
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Google Inc, CN=Google Internet Authority G2
        Validity
            Not Before: Jan 15 12:20:52 2016 GMT
            Not After : Apr 14 00:00:00 2016 GMT
        Subject: C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:86:dc:45:a2:5c:0d:24:11:ae:85:84:46:0e:23:
                    45:d8:0b:fd:8d:3b:74:73:6b:e4:e6:62:c1:ac:ef:
                    6d:77:68:45:ca:fc:34:07:47:cf:a7:16:e4:3a:6e:
                    f6:09:de:0e:9c:65:57:c4:80:74:86:9d:57:45:65:
                    ee:c8:ff:a9:14:c1:e6:5d:2b:21:55:60:c8:ad:c0:
                    30:8d:1e:6b:f9:69:c0:aa:b2:da:71:92:4d:1e:40:
                    ce:58:ef:82:39:8f:02:50:71:93:9f:d6:1f:c0:ac:
                    2e:1d:04:4e:a7:a6:87:62:ee:d8:86:9a:4c:5e:ed:
                    dd:2f:59:19:e7:90:33:61:dc:20:61:57:3a:05:dc:
                    66:0e:c1:96:45:96:e0:67:4a:ad:fd:04:02:d3:39:
                    9b:47:e8:4b:a5:90:0a:84:79:8d:56:70:51:5d:8c:
                    f9:ab:e5:cb:10:19:a3:42:7c:15:9b:03:33:3c:2b:
                    d9:17:33:44:59:a9:f4:c1:0b:02:46:a7:09:d7:d9:
                    4e:e6:12:f1:9f:83:b6:4f:bd:7c:a8:5d:a1:71:dd:
                    6c:1f:54:4b:e8:79:61:53:12:5e:d3:d2:f7:ca:81:
                    82:32:81:0d:22:ae:b2:c0:8a:d5:80:5b:19:b7:28:
                    60:f1:33:32:09:9b:91:b7:20:92:fa:ec:7d:99:ad:
                    00:ef
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Alternative Name: 
                DNS:www.google.com
            Authority Information Access: 
                CA Issuers - URI:http://pki.google.com/GIAG2.crt
                OCSP - URI:http://clients1.google.com/ocsp

            X509v3 Subject Key Identifier: 
                9F:FB:21:7B:F9:2B:DF:0F:8E:2F:0F:65:C2:72:A5:AF:9C:0E:6F:D4
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier: 
                keyid:4A:DD:06:16:1B:BC:F6:68:B5:76:F5:81:B6:BB:62:1A:BA:5A:81:2F

            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.11129.2.5.1
                Policy: 2.23.140.1.2.2

            X509v3 CRL Distribution Points: 
                URI:http://pki.google.com/GIAG2.crl

    Signature Algorithm: sha256WithRSAEncryption
        95:ef:38:55:18:dc:c9:67:c4:11:17:ef:57:de:f1:3a:bf:0d:
        0b:fc:2e:f1:2f:be:cd:ee:a5:19:94:18:7c:72:14:b8:e6:d0:
        da:b9:f7:79:31:3b:49:f5:1b:66:47:68:43:80:14:1e:8c:9f:
        3d:bb:77:e2:c9:7c:c4:ab:b2:10:39:ae:0a:0c:55:48:bc:a1:
        77:03:84:e9:56:8e:8f:61:fe:4b:57:c6:78:df:69:9c:4a:60:
        eb:00:b6:96:c1:ec:0f:24:42:1b:5d:9f:10:18:10:6e:e3:72:
        8d:3c:e9:a2:90:b1:4c:f1:2a:21:74:dd:d1:d5:92:33:61:bc:
        52:46:bd:c6:65:e6:37:aa:7d:39:ad:75:ef:87:89:e0:e9:eb:
        de:9f:a9:9a:47:1a:9e:99:ee:7a:62:60:12:ed:14:0c:f8:63:
        f8:5d:3e:8a:ab:83:d5:4c:36:9f:a7:ef:8e:09:51:ff:c1:68:
        c1:82:6b:7c:29:f5:6e:25:5d:44:7f:5e:64:0e:33:e8:c4:fc:
        40:5d:67:9e:56:d8:d7:77:bf:bb:5b:13:db:2c:35:d5:43:82:
        0f:f5:c3:9b:ff:ec:2f:38:00:db:36:39:df:4e:85:20:d1:08:
        57:a0:f9:4d:cc:8f:64:bf:35:05:f9:98:58:f3:6a:55:54:13:
        d1:77:92:dd
-----BEGIN CERTIFICATE-----
MIIEgDCCA2igAwIBAgIIATBc0EORnYYwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTYwMTE1MTIyMDUyWhcNMTYwNDE0MDAwMDAw
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCG3EWi
XA0kEa6FhEYOI0XYC/2NO3Rza+TmYsGs7213aEXK/DQHR8+nFuQ6bvYJ3g6cZVfE
gHSGnVdFZe7I/6kUweZdKyFVYMitwDCNHmv5acCqstpxkk0eQM5Y74I5jwJQcZOf
1h/ArC4dBE6npodi7tiGmkxe7d0vWRnnkDNh3CBhVzoF3GYOwZZFluBnSq39BALT
OZtH6EulkAqEeY1WcFFdjPmr5csQGaNCfBWbAzM8K9kXM0RZqfTBCwJGpwnX2U7m
EvGfg7ZPvXyoXaFx3WwfVEvoeWFTEl7T0vfKgYIygQ0irrLAitWAWxm3KGDxMzIJ
m5G3IJL67H2ZrQDvAgMBAAGjggFLMIIBRzAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
A1UdDgQWBBSf+yF7+SvfD44vD2XCcqWvnA5v1DAMBgNVHRMBAf8EAjAAMB8GA1Ud
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHW
eQIFATAIBgZngQwBAgIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29n
bGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAle84VRjcyWfEERfv
V97xOr8NC/wu8S++ze6lGZQYfHIUuObQ2rn3eTE7SfUbZkdoQ4AUHoyfPbt34sl8
xKuyEDmuCgxVSLyhdwOE6VaOj2H+S1fGeN9pnEpg6wC2lsHsDyRCG12fEBgQbuNy
jTzpopCxTPEqIXTd0dWSM2G8Uka9xmXmN6p9Oa1174eJ4Onr3p+pmkcanpnuemJg
Eu0UDPhj+F0+iquD1Uw2n6fvjglR/8FowYJrfCn1biVdRH9eZA4z6MT8QF1nnlbY
13e/u1sT2yw11UOCD/XDm//sLzgA2zY5306FINEIV6D5TcyPZL81BfmYWPNqVVQT
0XeS3Q==
-----END CERTIFICATE-----

Obtaining A Server’s Public CA Certificate Chain

Screen Shot 2016-01-23 at 7.34.52 PM Screen Shot 2016-01-23 at 7.35.13 PM

openssl s_client -connect www.google.com:443 -showcerts

CONNECTED(00000003)
depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=google.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
-----BEGIN CERTIFICATE-----
MIIf+DCCHuCgAwIBAgIICakyfYEPpYQwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTYwMTE1MTIxMjU1WhcNMTYwNDE0MDAwMDAw
WjBkMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzETMBEGA1UEAwwKZ29v
Z2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPcEGWpooVGn
J7zMUVHcp9BENDMB01hNJAHbhBJUVFTGQzeZzu6EGtTh9HKJfejqzpAaTkC8Q1ZI
gAUF5A8q4JKfs+C3YoxOXggEAvuSVA+I8UtPyVY0nJr1oumG18o9bTi8T2ABPlBq
Ef0BXhukoi8F6uYRbxBDEWjjKuOkw5sDWqw8cFoFRA7Ly2C+S5oR53s0Lhgo0T3G
zkRUT3WxwZrHFcBdeMUQn+Jd5WgfvkGGbUKGYINKZzGSc129MwL2NMF3MpKm0bi+
JDDebYfmt6LoSCTxLRhiXrfo38cwMZWYNZIK42hhteiREmKKzM1G/KpzgsuJ/wRc
dwdagyDnxGUCAwEAAaOCHMcwghzDMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjCCG5MGA1UdEQSCG4owghuGggpnb29nbGUuY29tggoqLjJtZG4ubmV0gg0q
LmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tghQqLmF1LmRvdWJs
ZWNsaWNrLm5ldIILKi5jYy1kdC5jb22CEiouY2xvdWQuZ29vZ2xlLmNvbYIUKi5k
ZS5kb3VibGVjbGljay5uZXSCESouZG91YmxlY2xpY2suY29tghEqLmRvdWJsZWNs
aWNrLm5ldIIVKi5mbHMuZG91YmxlY2xpY2submV0ghQqLmZyLmRvdWJsZWNsaWNr
Lm5ldIIWKi5nb29nbGUtYW5hbHl0aWNzLmNvbYILKi5nb29nbGUuYWOCCyouZ29v
Z2xlLmFkggsqLmdvb2dsZS5hZYILKi5nb29nbGUuYWaCCyouZ29vZ2xlLmFnggsq
Lmdvb2dsZS5hbIILKi5nb29nbGUuYW2CCyouZ29vZ2xlLmFzggsqLmdvb2dsZS5h
dIILKi5nb29nbGUuYXqCCyouZ29vZ2xlLmJhggsqLmdvb2dsZS5iZYILKi5nb29n
bGUuYmaCCyouZ29vZ2xlLmJnggsqLmdvb2dsZS5iaYILKi5nb29nbGUuYmqCCyou
Z29vZ2xlLmJzggsqLmdvb2dsZS5idIILKi5nb29nbGUuYnmCCyouZ29vZ2xlLmNh
ggwqLmdvb2dsZS5jYXSCCyouZ29vZ2xlLmNjggsqLmdvb2dsZS5jZIILKi5nb29n
bGUuY2aCCyouZ29vZ2xlLmNnggsqLmdvb2dsZS5jaIILKi5nb29nbGUuY2mCCyou
Z29vZ2xlLmNsggsqLmdvb2dsZS5jbYILKi5nb29nbGUuY26CDiouZ29vZ2xlLmNv
LmFvgg4qLmdvb2dsZS5jby5id4IOKi5nb29nbGUuY28uY2uCDiouZ29vZ2xlLmNv
LmNygg4qLmdvb2dsZS5jby5odYIOKi5nb29nbGUuY28uaWSCDiouZ29vZ2xlLmNv
Lmlsgg4qLmdvb2dsZS5jby5pbYIOKi5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNv
Lmplgg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28ua2WCDiouZ29vZ2xlLmNv
Lmtygg4qLmdvb2dsZS5jby5sc4IOKi5nb29nbGUuY28ubWGCDiouZ29vZ2xlLmNv
Lm16gg4qLmdvb2dsZS5jby5ueoIOKi5nb29nbGUuY28udGiCDiouZ29vZ2xlLmNv
LnR6gg4qLmdvb2dsZS5jby51Z4IOKi5nb29nbGUuY28udWuCDiouZ29vZ2xlLmNv
LnV6gg4qLmdvb2dsZS5jby52ZYIOKi5nb29nbGUuY28udmmCDiouZ29vZ2xlLmNv
Lnphgg4qLmdvb2dsZS5jby56bYIOKi5nb29nbGUuY28ueneCDCouZ29vZ2xlLmNv
bYIPKi5nb29nbGUuY29tLmFmgg8qLmdvb2dsZS5jb20uYWeCDyouZ29vZ2xlLmNv
bS5haYIPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xl
LmNvbS5iZIIPKi5nb29nbGUuY29tLmJogg8qLmdvb2dsZS5jb20uYm6CDyouZ29v
Z2xlLmNvbS5ib4IPKi5nb29nbGUuY29tLmJygg8qLmdvb2dsZS5jb20uYnmCDyou
Z29vZ2xlLmNvbS5ieoIPKi5nb29nbGUuY29tLmNugg8qLmdvb2dsZS5jb20uY2+C
DyouZ29vZ2xlLmNvbS5jdYIPKi5nb29nbGUuY29tLmN5gg8qLmdvb2dsZS5jb20u
ZG+CDyouZ29vZ2xlLmNvbS5lY4IPKi5nb29nbGUuY29tLmVngg8qLmdvb2dsZS5j
b20uZXSCDyouZ29vZ2xlLmNvbS5maoIPKi5nb29nbGUuY29tLmdlgg8qLmdvb2ds
ZS5jb20uZ2iCDyouZ29vZ2xlLmNvbS5naYIPKi5nb29nbGUuY29tLmdygg8qLmdv
b2dsZS5jb20uZ3SCDyouZ29vZ2xlLmNvbS5oa4IPKi5nb29nbGUuY29tLmlxgg8q
Lmdvb2dsZS5jb20uam2CDyouZ29vZ2xlLmNvbS5qb4IPKi5nb29nbGUuY29tLmto
gg8qLmdvb2dsZS5jb20ua3eCDyouZ29vZ2xlLmNvbS5sYoIPKi5nb29nbGUuY29t
Lmx5gg8qLmdvb2dsZS5jb20ubW2CDyouZ29vZ2xlLmNvbS5tdIIPKi5nb29nbGUu
Y29tLm14gg8qLmdvb2dsZS5jb20ubXmCDyouZ29vZ2xlLmNvbS5uYYIPKi5nb29n
bGUuY29tLm5mgg8qLmdvb2dsZS5jb20ubmeCDyouZ29vZ2xlLmNvbS5uaYIPKi5n
b29nbGUuY29tLm5wgg8qLmdvb2dsZS5jb20ubnKCDyouZ29vZ2xlLmNvbS5vbYIP
Ki5nb29nbGUuY29tLnBhgg8qLmdvb2dsZS5jb20ucGWCDyouZ29vZ2xlLmNvbS5w
Z4IPKi5nb29nbGUuY29tLnBogg8qLmdvb2dsZS5jb20ucGuCDyouZ29vZ2xlLmNv
bS5wbIIPKi5nb29nbGUuY29tLnBygg8qLmdvb2dsZS5jb20ucHmCDyouZ29vZ2xl
LmNvbS5xYYIPKi5nb29nbGUuY29tLnJ1gg8qLmdvb2dsZS5jb20uc2GCDyouZ29v
Z2xlLmNvbS5zYoIPKi5nb29nbGUuY29tLnNngg8qLmdvb2dsZS5jb20uc2yCDyou
Z29vZ2xlLmNvbS5zdoIPKi5nb29nbGUuY29tLnRqgg8qLmdvb2dsZS5jb20udG6C
DyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnR3gg8qLmdvb2dsZS5jb20u
dWGCDyouZ29vZ2xlLmNvbS51eYIPKi5nb29nbGUuY29tLnZjgg8qLmdvb2dsZS5j
b20udmWCDyouZ29vZ2xlLmNvbS52boILKi5nb29nbGUuY3aCCyouZ29vZ2xlLmN6
ggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZGqCCyouZ29vZ2xlLmRrggsqLmdvb2ds
ZS5kbYILKi5nb29nbGUuZHqCCyouZ29vZ2xlLmVlggsqLmdvb2dsZS5lc4IMKi5n
b29nbGUuZXVzggsqLmdvb2dsZS5maYILKi5nb29nbGUuZm2CCyouZ29vZ2xlLmZy
ggwqLmdvb2dsZS5mcmyCCyouZ29vZ2xlLmdhggwqLmdvb2dsZS5nYWyCCyouZ29v
Z2xlLmdlggsqLmdvb2dsZS5nZ4ILKi5nb29nbGUuZ2yCCyouZ29vZ2xlLmdtggsq
Lmdvb2dsZS5ncIILKi5nb29nbGUuZ3KCCyouZ29vZ2xlLmd5ggsqLmdvb2dsZS5o
a4ILKi5nb29nbGUuaG6CCyouZ29vZ2xlLmhyggsqLmdvb2dsZS5odIILKi5nb29n
bGUuaHWCCyouZ29vZ2xlLmllggsqLmdvb2dsZS5pbYILKi5nb29nbGUuaW6CDSou
Z29vZ2xlLmluZm+CCyouZ29vZ2xlLmlxggsqLmdvb2dsZS5pcoILKi5nb29nbGUu
aXOCCyouZ29vZ2xlLml0gg4qLmdvb2dsZS5pdC5hb4ILKi5nb29nbGUuamWCCyou
Z29vZ2xlLmpvgg0qLmdvb2dsZS5qb2JzggsqLmdvb2dsZS5qcIILKi5nb29nbGUu
a2eCCyouZ29vZ2xlLmtpggsqLmdvb2dsZS5reoILKi5nb29nbGUubGGCCyouZ29v
Z2xlLmxpggsqLmdvb2dsZS5sa4ILKi5nb29nbGUubHSCCyouZ29vZ2xlLmx1ggsq
Lmdvb2dsZS5sdoILKi5nb29nbGUubWSCCyouZ29vZ2xlLm1lggsqLmdvb2dsZS5t
Z4ILKi5nb29nbGUubWuCCyouZ29vZ2xlLm1sggsqLmdvb2dsZS5tboILKi5nb29n
bGUubXOCCyouZ29vZ2xlLm11ggsqLmdvb2dsZS5tdoILKi5nb29nbGUubXeCCyou
Z29vZ2xlLm5lgg4qLmdvb2dsZS5uZS5qcIIMKi5nb29nbGUubmV0ggsqLmdvb2ds
ZS5uZ4ILKi5nb29nbGUubmyCCyouZ29vZ2xlLm5vggsqLmdvb2dsZS5ucoILKi5n
b29nbGUubnWCDyouZ29vZ2xlLm9mZi5haYILKi5nb29nbGUucGuCCyouZ29vZ2xl
LnBsggsqLmdvb2dsZS5wboILKi5nb29nbGUucHOCCyouZ29vZ2xlLnB0ggsqLmdv
b2dsZS5yb4ILKi5nb29nbGUucnOCCyouZ29vZ2xlLnJ1ggsqLmdvb2dsZS5yd4IL
Ki5nb29nbGUuc2OCCyouZ29vZ2xlLnNlggsqLmdvb2dsZS5zaIILKi5nb29nbGUu
c2mCCyouZ29vZ2xlLnNrggsqLmdvb2dsZS5zbYILKi5nb29nbGUuc26CCyouZ29v
Z2xlLnNvggsqLmdvb2dsZS5zcoILKi5nb29nbGUuc3SCCyouZ29vZ2xlLnRkggwq
Lmdvb2dsZS50ZWyCCyouZ29vZ2xlLnRnggsqLmdvb2dsZS50a4ILKi5nb29nbGUu
dGyCCyouZ29vZ2xlLnRtggsqLmdvb2dsZS50boILKi5nb29nbGUudG+CCyouZ29v
Z2xlLnR0ggsqLmdvb2dsZS51YYILKi5nb29nbGUudXOCCyouZ29vZ2xlLnV6ggsq
Lmdvb2dsZS52Z4ILKi5nb29nbGUudnWCCyouZ29vZ2xlLndzghIqLmdvb2dsZWFk
YXBpcy5jb22CFSouZ29vZ2xlYWRzc2VydmluZy5jboIPKi5nb29nbGVhcGlzLmNu
ghQqLmdvb2dsZWNvbW1lcmNlLmNvbYIRKi5nb29nbGV2aWRlby5jb22CDCouZ3N0
YXRpYy5jboINKi5nc3RhdGljLmNvbYIKKi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIU
Ki5qcC5kb3VibGVjbGljay5uZXSCFCoubWV0cmljLmdzdGF0aWMuY29tghQqLnVr
LmRvdWJsZWNsaWNrLm5ldIIMKi51cmNoaW4uY29tghAqLnVybC5nb29nbGUuY29t
ghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYqLnlvdXR1
YmVlZHVjYXRpb24uY29tggsqLnl0aW1nLmNvbYIVYWQubW8uZG91YmxlY2xpY2su
bmV0ghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CD2Rv
dWJsZWNsaWNrLm5ldIIEZy5jb4IGZ29vLmdsghRnb29nbGUtYW5hbHl0aWNzLmNv
bYIJZ29vZ2xlLmFjgglnb29nbGUuYWSCCWdvb2dsZS5hZYIJZ29vZ2xlLmFmggln
b29nbGUuYWeCCWdvb2dsZS5hbIIJZ29vZ2xlLmFtgglnb29nbGUuYXOCCWdvb2ds
ZS5hdIIJZ29vZ2xlLmF6gglnb29nbGUuYmGCCWdvb2dsZS5iZYIJZ29vZ2xlLmJm
gglnb29nbGUuYmeCCWdvb2dsZS5iaYIJZ29vZ2xlLmJqgglnb29nbGUuYnOCCWdv
b2dsZS5idIIJZ29vZ2xlLmJ5gglnb29nbGUuY2GCCmdvb2dsZS5jYXSCCWdvb2ds
ZS5jY4IJZ29vZ2xlLmNkgglnb29nbGUuY2aCCWdvb2dsZS5jZ4IJZ29vZ2xlLmNo
gglnb29nbGUuY2mCCWdvb2dsZS5jbIIJZ29vZ2xlLmNtgglnb29nbGUuY26CDGdv
b2dsZS5jby5hb4IMZ29vZ2xlLmNvLmJ3ggxnb29nbGUuY28uY2uCDGdvb2dsZS5j
by5jcoIMZ29vZ2xlLmNvLmh1ggxnb29nbGUuY28uaWSCDGdvb2dsZS5jby5pbIIM
Z29vZ2xlLmNvLmltggxnb29nbGUuY28uaW6CDGdvb2dsZS5jby5qZYIMZ29vZ2xl
LmNvLmpwggxnb29nbGUuY28ua2WCDGdvb2dsZS5jby5rcoIMZ29vZ2xlLmNvLmxz
ggxnb29nbGUuY28ubWGCDGdvb2dsZS5jby5teoIMZ29vZ2xlLmNvLm56ggxnb29n
bGUuY28udGiCDGdvb2dsZS5jby50eoIMZ29vZ2xlLmNvLnVnggxnb29nbGUuY28u
dWuCDGdvb2dsZS5jby51eoIMZ29vZ2xlLmNvLnZlggxnb29nbGUuY28udmmCDGdv
b2dsZS5jby56YYIMZ29vZ2xlLmNvLnptggxnb29nbGUuY28ueneCDWdvb2dsZS5j
b20uYWaCDWdvb2dsZS5jb20uYWeCDWdvb2dsZS5jb20uYWmCDWdvb2dsZS5jb20u
YXKCDWdvb2dsZS5jb20uYXWCDWdvb2dsZS5jb20uYmSCDWdvb2dsZS5jb20uYmiC
DWdvb2dsZS5jb20uYm6CDWdvb2dsZS5jb20uYm+CDWdvb2dsZS5jb20uYnKCDWdv
b2dsZS5jb20uYnmCDWdvb2dsZS5jb20uYnqCDWdvb2dsZS5jb20uY26CDWdvb2ds
ZS5jb20uY2+CDWdvb2dsZS5jb20uY3WCDWdvb2dsZS5jb20uY3mCDWdvb2dsZS5j
b20uZG+CDWdvb2dsZS5jb20uZWOCDWdvb2dsZS5jb20uZWeCDWdvb2dsZS5jb20u
ZXSCDWdvb2dsZS5jb20uZmqCDWdvb2dsZS5jb20uZ2WCDWdvb2dsZS5jb20uZ2iC
DWdvb2dsZS5jb20uZ2mCDWdvb2dsZS5jb20uZ3KCDWdvb2dsZS5jb20uZ3SCDWdv
b2dsZS5jb20uaGuCDWdvb2dsZS5jb20uaXGCDWdvb2dsZS5jb20uam2CDWdvb2ds
ZS5jb20uam+CDWdvb2dsZS5jb20ua2iCDWdvb2dsZS5jb20ua3eCDWdvb2dsZS5j
b20ubGKCDWdvb2dsZS5jb20ubHmCDWdvb2dsZS5jb20ubW2CDWdvb2dsZS5jb20u
bXSCDWdvb2dsZS5jb20ubXiCDWdvb2dsZS5jb20ubXmCDWdvb2dsZS5jb20ubmGC
DWdvb2dsZS5jb20ubmaCDWdvb2dsZS5jb20ubmeCDWdvb2dsZS5jb20ubmmCDWdv
b2dsZS5jb20ubnCCDWdvb2dsZS5jb20ubnKCDWdvb2dsZS5jb20ub22CDWdvb2ds
ZS5jb20ucGGCDWdvb2dsZS5jb20ucGWCDWdvb2dsZS5jb20ucGeCDWdvb2dsZS5j
b20ucGiCDWdvb2dsZS5jb20ucGuCDWdvb2dsZS5jb20ucGyCDWdvb2dsZS5jb20u
cHKCDWdvb2dsZS5jb20ucHmCDWdvb2dsZS5jb20ucWGCDWdvb2dsZS5jb20ucnWC
DWdvb2dsZS5jb20uc2GCDWdvb2dsZS5jb20uc2KCDWdvb2dsZS5jb20uc2eCDWdv
b2dsZS5jb20uc2yCDWdvb2dsZS5jb20uc3aCDWdvb2dsZS5jb20udGqCDWdvb2ds
ZS5jb20udG6CDWdvb2dsZS5jb20udHKCDWdvb2dsZS5jb20udHeCDWdvb2dsZS5j
b20udWGCDWdvb2dsZS5jb20udXmCDWdvb2dsZS5jb20udmOCDWdvb2dsZS5jb20u
dmWCDWdvb2dsZS5jb20udm6CCWdvb2dsZS5jdoIJZ29vZ2xlLmN6gglnb29nbGUu
ZGWCCWdvb2dsZS5kaoIJZ29vZ2xlLmRrgglnb29nbGUuZG2CCWdvb2dsZS5keoIJ
Z29vZ2xlLmVlgglnb29nbGUuZXOCCmdvb2dsZS5ldXOCCWdvb2dsZS5maYIJZ29v
Z2xlLmZtgglnb29nbGUuZnKCCmdvb2dsZS5mcmyCCWdvb2dsZS5nYYIKZ29vZ2xl
LmdhbIIJZ29vZ2xlLmdlgglnb29nbGUuZ2eCCWdvb2dsZS5nbIIJZ29vZ2xlLmdt
gglnb29nbGUuZ3CCCWdvb2dsZS5ncoIJZ29vZ2xlLmd5gglnb29nbGUuaGuCCWdv
b2dsZS5oboIJZ29vZ2xlLmhygglnb29nbGUuaHSCCWdvb2dsZS5odYIJZ29vZ2xl
Lmllgglnb29nbGUuaW2CCWdvb2dsZS5pboILZ29vZ2xlLmluZm+CCWdvb2dsZS5p
cYIJZ29vZ2xlLmlygglnb29nbGUuaXOCCWdvb2dsZS5pdIIMZ29vZ2xlLml0LmFv
gglnb29nbGUuamWCCWdvb2dsZS5qb4ILZ29vZ2xlLmpvYnOCCWdvb2dsZS5qcIIJ
Z29vZ2xlLmtngglnb29nbGUua2mCCWdvb2dsZS5reoIJZ29vZ2xlLmxhgglnb29n
bGUubGmCCWdvb2dsZS5sa4IJZ29vZ2xlLmx0gglnb29nbGUubHWCCWdvb2dsZS5s
doIJZ29vZ2xlLm1kgglnb29nbGUubWWCCWdvb2dsZS5tZ4IJZ29vZ2xlLm1rggln
b29nbGUubWyCCWdvb2dsZS5tboIJZ29vZ2xlLm1zgglnb29nbGUubXWCCWdvb2ds
ZS5tdoIJZ29vZ2xlLm13gglnb29nbGUubmWCDGdvb2dsZS5uZS5qcIIKZ29vZ2xl
Lm5ldIIJZ29vZ2xlLm5ngglnb29nbGUubmyCCWdvb2dsZS5ub4IJZ29vZ2xlLm5y
gglnb29nbGUubnWCDWdvb2dsZS5vZmYuYWmCCWdvb2dsZS5wa4IJZ29vZ2xlLnBs
gglnb29nbGUucG6CCWdvb2dsZS5wc4IJZ29vZ2xlLnB0gglnb29nbGUucm+CCWdv
b2dsZS5yc4IJZ29vZ2xlLnJ1gglnb29nbGUucneCCWdvb2dsZS5zY4IJZ29vZ2xl
LnNlgglnb29nbGUuc2iCCWdvb2dsZS5zaYIJZ29vZ2xlLnNrgglnb29nbGUuc22C
CWdvb2dsZS5zboIJZ29vZ2xlLnNvgglnb29nbGUuc3KCCWdvb2dsZS5zdIIJZ29v
Z2xlLnRkggpnb29nbGUudGVsgglnb29nbGUudGeCCWdvb2dsZS50a4IJZ29vZ2xl
LnRsgglnb29nbGUudG2CCWdvb2dsZS50boIJZ29vZ2xlLnRvgglnb29nbGUudHSC
CWdvb2dsZS51YYIJZ29vZ2xlLnVzgglnb29nbGUudXqCCWdvb2dsZS52Z4IJZ29v
Z2xlLnZ1gglnb29nbGUud3OCEmdvb2dsZWNvbW1lcmNlLmNvbYILZ3N0YXRpYy5j
b22CCnVyY2hpbi5jb22CCHlvdXR1LmJlggt5b3V0dWJlLmNvbYIUeW91dHViZWVk
dWNhdGlvbi5jb20waAYIKwYBBQUHAQEEXDBaMCsGCCsGAQUFBzAChh9odHRwOi8v
cGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0MCsGCCsGAQUFBzABhh9odHRwOi8vY2xp
ZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0GA1UdDgQWBBRV64RQzHpTPCAms0fQrZRz
vueE3zAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFErdBhYbvPZotXb1gba7Yhq6
WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFATAIBgZngQwBAgIwMAYDVR0fBCkw
JzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG
9w0BAQsFAAOCAQEAX16cJNFG2m/ZrIzSqo/ktkNo3CPnXtsgmSQLwqYs2av0VlFz
EDfK61gS8+asgXsqlhDrsKM38Ehz1NkAGISHBFqzpUVzxjA+DVV/j+dU3xOSlOCN
jENuZzXLIGI10Zu7DDwBHPohAHJ5+UMyBnF7XBPFitOBu2ShZd9HFIeigXZwhsmV
DYTrITcGDlitMEa5ulZ9LhvJEat/6GcTg/Eshbf6YSpClAWlr8q7XNh9kWtdixv1
U7z+Uw2IzwoqzWzluFTQH0P/f1Jjn9JOILKDckPP0obk38z1MGKyEpHP1G2b5bDu
dPbx2gOKuwEeUlFKZIwBAxnNK360EQNE39b0Wg==
-----END CERTIFICATE-----
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIDAjqDMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU2WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD
VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov
L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig
JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ
MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEAqvqpIM1qZ4PtXtR+
3h3Ef+AlBgDFJPupyC1tft6dgmUsgWM0Zj7pUsIItMsv91+ZOmqcUHqFBYx90SpI
hNMJbHzCzTWf84LuUt5oX+QAihcglvcpjZpNy6jehsgNb1aHA30DP9z6eX0hGfnI
Oi9RdozHQZJxjyXON/hKTAAj78Q1EK7gI4BzfE00LshukNYQHpmEcxpw8u1VDu4X
Bupn7jLrLN1nBz/2i8Jw3lsA5rsb0zYaImxssDVCbJAJPZPpZAkiDoUGn8JzIdPm
X4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJkFleW2V40
fsg12A==
-----END CERTIFICATE-----
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=google.com
issuer=/C=US/O=Google Inc/CN=Google Internet Authority G2
---
No client certificate CA names sent
---
SSL handshake has read 10272 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES128-SHA
    Session-ID: A7E5F54D45DB7744E515B342802490A1D6748E9F94820BF708CDC4C6AD7A487D
    Session-ID-ctx: 
    Master-Key: 2D612A2B19DC6274481C68B9FEE2B274B27080CF1D9B60177EB0B45BDFDCF32D14D312B338DB3E16BEE8434123EE4009
    Key-Arg   : None
    Start Time: 1453595583
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

Related Links for SSL and Cert Pinning on Android:

Tools for Decoding Certificates:

Contactless Payments on Capital One Wallet for Android!

It’s been super hard to not share this info as I’ve done presentations on Host Card Emulation (HCE) presentations, but on October 14th the feature I’ve been leading Android development efforts on launched! Capital One Wallet – Google Play Store. This is a project I’ve been a part of for almost a year and it’s so cool to see it in the wild and right along side of Android Pay, Samsung Pay and the rest. It supports Visa and Mastercard and is pretty awesome. Capital One was the first bank in the US to support contactless payments in an Android app and it’s super exciting to have been a part of that.

I tried to do my with presentations but it always killed me that I wasn’t able to share what we were doing. I did feel like I was able to explain how HCE works on Android, but wasn’t able to give much more info at the time. Check out my presentation video and slides from Droidcon NYC.

Tap to Pay Screen
Tap to Pay
Payment Sent Screen
Payment Sent