summaryrefslogtreecommitdiff
path: root/samples/KeyChainDemo/src/com/example/android/keychain/SecureWebServer.java
blob: 8f84000afef53588c3a516a7486a1e7f401dcf4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * 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 "";
    }

}