Home | History | Annotate | Download | only in keychain
      1 /*
      2  * Copyright 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.keychain;
     18 
     19 import java.io.BufferedInputStream;
     20 import java.io.BufferedReader;
     21 import java.io.FileInputStream;
     22 import java.io.IOException;
     23 import java.io.InputStreamReader;
     24 import java.io.PrintWriter;
     25 import java.net.Socket;
     26 import java.security.KeyStore;
     27 
     28 import javax.net.ssl.KeyManagerFactory;
     29 import javax.net.ssl.SSLContext;
     30 import javax.net.ssl.SSLServerSocket;
     31 import javax.net.ssl.SSLServerSocketFactory;
     32 
     33 import android.content.Context;
     34 import android.util.Base64;
     35 import android.util.Log;
     36 
     37 public class SecureWebServer {
     38 
     39     // Log tag for this class
     40     private static final String TAG = "SecureWebServer";
     41 
     42     // File name of the image used in server response
     43     private static final String EMBEDDED_IMAGE_FILENAME = "training-prof.png";
     44 
     45     private SSLServerSocketFactory sssf;
     46     private SSLServerSocket sss;
     47 
     48     // A flag to control whether the web server should be kept running
     49     private boolean isRunning = true;
     50 
     51     // The base64 encoded image string used as an embedded image
     52     private final String base64Image;
     53 
     54     /**
     55      * WebServer constructor.
     56      */
     57     public SecureWebServer(Context ctx) {
     58         try {
     59             // Get an SSL context using the TLS protocol
     60             SSLContext sslContext = SSLContext.getInstance("TLS");
     61 
     62             // Get a key manager factory using the default algorithm
     63             KeyManagerFactory kmf = KeyManagerFactory
     64                     .getInstance(KeyManagerFactory.getDefaultAlgorithm());
     65 
     66             // Load the PKCS12 key chain
     67             KeyStore ks = KeyStore.getInstance("PKCS12");
     68             FileInputStream fis = ctx.getAssets()
     69                     .openFd(KeyChainDemoActivity.PKCS12_FILENAME)
     70                     .createInputStream();
     71             ks.load(fis, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray());
     72             kmf.init(ks, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray());
     73 
     74             // Initialize the SSL context
     75             sslContext.init(kmf.getKeyManagers(), null, null);
     76 
     77             // Create the SSL server socket factory
     78             sssf = sslContext.getServerSocketFactory();
     79 
     80         } catch (Exception e) {
     81             e.printStackTrace();
     82         }
     83 
     84         // Create the base64 image string used in the server response
     85         base64Image = createBase64Image(ctx);
     86     }
     87 
     88     /**
     89      * This method starts the web server listening to the port 8080
     90      */
     91     protected void start() {
     92 
     93         new Thread(new Runnable() {
     94 
     95             @Override
     96             public void run() {
     97                 Log.d(TAG, "Secure Web Server is starting up on port 8080");
     98                 try {
     99                     // Create the secure server socket
    100                     sss = (SSLServerSocket) sssf.createServerSocket(8080);
    101                 } catch (Exception e) {
    102                     System.out.println("Error: " + e);
    103                     return;
    104                 }
    105 
    106                 Log.d(TAG, "Waiting for connection");
    107                 while (isRunning) {
    108                     try {
    109                         // Wait for an SSL connection
    110                         Socket socket = sss.accept();
    111 
    112                         // Got a connection
    113                         Log.d(TAG, "Connected, sending data.");
    114 
    115                         BufferedReader in = new BufferedReader(
    116                                 new InputStreamReader(socket.getInputStream()));
    117                         PrintWriter out = new PrintWriter(socket
    118                                 .getOutputStream());
    119 
    120                         // Read the data until a blank line is reached which
    121                         // signifies the end of the client HTTP headers
    122                         String str = ".";
    123                         while (!str.equals(""))
    124                             str = in.readLine();
    125 
    126                         // Send a HTTP response
    127                         out.println("HTTP/1.0 200 OK");
    128                         out.println("Content-Type: text/html");
    129                         out.println("Server: Android KeyChainiDemo SSL Server");
    130                         // this blank line signals the end of the headers
    131                         out.println("");
    132                         // Send the HTML page
    133                         out.println("<H1>Welcome to Android!</H1>");
    134                         // Add an embedded Android image
    135                         out.println("<img src='data:image/png;base64," + base64Image + "'/>");
    136                         out.flush();
    137                         socket.close();
    138                     } catch (Exception e) {
    139                         Log.d(TAG, "Error: " + e);
    140                     }
    141                 }
    142             }
    143         }).start();
    144 
    145     }
    146 
    147     /**
    148      * This method stops the SSL web server
    149      */
    150     protected void stop() {
    151         try {
    152             // Break out from the infinite while loop in start()
    153             isRunning = false;
    154 
    155             // Close the socket
    156             if (sss != null) {
    157                 sss.close();
    158             }
    159         } catch (IOException e) {
    160             e.printStackTrace();
    161         }
    162     }
    163 
    164     /**
    165      * This method reads a binary image from the assets folder and returns the
    166      * base64 encoded image string.
    167      *
    168      * @param ctx The service this web server is running in.
    169      * @return String The base64 encoded image string or "" if there is an
    170      *         exception
    171      */
    172     private String createBase64Image(Context ctx) {
    173         BufferedInputStream bis;
    174         try {
    175             bis = new BufferedInputStream(ctx.getAssets().open(EMBEDDED_IMAGE_FILENAME));
    176             byte[] embeddedImage = new byte[bis.available()];
    177             bis.read(embeddedImage);
    178             return Base64.encodeToString(embeddedImage, Base64.DEFAULT);
    179         } catch (IOException e) {
    180             e.printStackTrace();
    181         }
    182         return "";
    183     }
    184 
    185 }
    186