/* * Copyright 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.keychain; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.security.KeyStore; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import android.content.Context; import android.util.Base64; import android.util.Log; public class SecureWebServer { // Log tag for this class private static final String TAG = "SecureWebServer"; // File name of the image used in server response private static final String EMBEDDED_IMAGE_FILENAME = "training-prof.png"; private SSLServerSocketFactory sssf; private SSLServerSocket sss; // A flag to control whether the web server should be kept running private boolean isRunning = true; // The base64 encoded image string used as an embedded image private final String base64Image; /** * WebServer constructor. */ public SecureWebServer(Context ctx) { try { // Get an SSL context using the TLS protocol SSLContext sslContext = SSLContext.getInstance("TLS"); // Get a key manager factory using the default algorithm KeyManagerFactory kmf = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); // Load the PKCS12 key chain KeyStore ks = KeyStore.getInstance("PKCS12"); FileInputStream fis = ctx.getAssets() .openFd(KeyChainDemoActivity.PKCS12_FILENAME) .createInputStream(); ks.load(fis, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray()); kmf.init(ks, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray()); // Initialize the SSL context sslContext.init(kmf.getKeyManagers(), null, null); // Create the SSL server socket factory sssf = sslContext.getServerSocketFactory(); } catch (Exception e) { e.printStackTrace(); } // Create the base64 image string used in the server response base64Image = createBase64Image(ctx); } /** * This method starts the web server listening to the port 8080 */ protected void start() { new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "Secure Web Server is starting up on port 8080"); try { // Create the secure server socket sss = (SSLServerSocket) sssf.createServerSocket(8080); } catch (Exception e) { System.out.println("Error: " + e); return; } Log.d(TAG, "Waiting for connection"); while (isRunning) { try { // Wait for an SSL connection Socket socket = sss.accept(); // Got a connection Log.d(TAG, "Connected, sending data."); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket .getOutputStream()); // Read the data until a blank line is reached which // signifies the end of the client HTTP headers String str = "."; while (!str.equals("")) str = in.readLine(); // Send a HTTP response out.println("HTTP/1.0 200 OK"); out.println("Content-Type: text/html"); out.println("Server: Android KeyChainiDemo SSL Server"); // this blank line signals the end of the headers out.println(""); // Send the HTML page out.println("<H1>Welcome to Android!</H1>"); // Add an embedded Android image out.println("<img src='data:image/png;base64," + base64Image + "'/>"); out.flush(); socket.close(); } catch (Exception e) { Log.d(TAG, "Error: " + e); } } } }).start(); } /** * This method stops the SSL web server */ protected void stop() { try { // Break out from the infinite while loop in start() isRunning = false; // Close the socket if (sss != null) { sss.close(); } } catch (IOException e) { e.printStackTrace(); } } /** * This method reads a binary image from the assets folder and returns the * base64 encoded image string. * * @param ctx The service this web server is running in. * @return String The base64 encoded image string or "" if there is an * exception */ private String createBase64Image(Context ctx) { BufferedInputStream bis; try { bis = new BufferedInputStream(ctx.getAssets().open(EMBEDDED_IMAGE_FILENAME)); byte[] embeddedImage = new byte[bis.available()]; bis.read(embeddedImage); return Base64.encodeToString(embeddedImage, Base64.DEFAULT); } catch (IOException e) { e.printStackTrace(); } return ""; } }