blob: 8f84000afef53588c3a516a7486a1e7f401dcf4d [file] [log] [blame]
/*
* 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 "";
}
}