https = http + ssl? [小糊涂的灵感]

Any information transmitted over wireless links is subject to interception. Some of that information could be sensitive, such as credit card numbers and other personal data. To make handheld wireless devices more useful in an enterprise setting and for m-commerce, applications must protect their users' information, using encryption, authentication, and secure communications protocols.

E-commerce applications are already using successfully the secure Hypertext Transfer Protocol (HTTPS), which is HTTP over the Secure Sockets Layer (SSL) protocol originally developed by Netscape. SSL works nicely for e-commerce applications, and it is a viable means of securing wireless transactions for end-to-end m-commerce applications. As a matter of fact, Java-enabled devices that support SSL are already available from NTT DoCoMo and Motorola.

Sun has been working on a stripped-down version of SSL called "Kilobyte" SSL (kSSL), and has already delivered it as part of the MIDP 1.0.3 reference implementation and the J2METM Wireless Toolkit 1.0.3. This article first presents an overview of SSL and kSSL, then shows you how to:

Open connections to https:// URLs
Configure Tomcat to be a secure server
Generate your own certificates and import them
Use the MEKeyTool delivered with the J2ME Wireless Toolkit to manage certificates.

--------------------------------------------------------------------------------
Overview of SSL

The SSL protocol allows clients (Web browsers, typically) and HTTP servers to communicate over a secure connection. It offers encryption, source authentication, and data integrity as means to protect information exchanged over insecure, public networks.

Encryption protects data from unauthorized use by converting it to an apparently meaningless form before transmission. The data is encrypted by one side (the client or the server), transmitted, decrypted by the other side, then processed.

Source authentication is a method of verifying the data sender's identity. The first time a browser or other client attempts to communicate with a Web server over a secure connection, the server presents the client with a set of credentials in the form of a certificate.

Certificates are issued and validated by trusted authorities known as certification authorities (CAs). A certificate represents the public-key identity of a person. It is a signed document that says: I certify that the public key in this document belongs to the entity named in this document. Signed (certificate authority). Two of the most widely used CAs are VeriSign and Thawte.

Data integrity refers to means of ensuring that data has not been modified in transit.

Among the features of SSL that have made it the de facto standard vehicle for secure e-commerce transactions is its support for negotiable encryption and authentication algorithms. The designers of SSL realized that not all parties will use the same client software and consequently not all clients will include any particular encryption algorithm. The same is true for servers. The client and server at the two ends of a connection negotiate the encryption and decryption algorithms (cipher suites) during their initial handshake. It may turn out that they do not have sufficient algorithms in common, in which case the connection attempt will fail.

An extended version of SSL has been adopted as an Internet standard under the name Transport Layer Security (TLS).

While SSL allows both the client and the server to authenticate each other, typically only the server is authenticated in the SSL layer. Clients are customarily authenticated in the application layer, through the use of passwords sent over an SSL-protected channel. This pattern is common in banking, stock trading, and other secure Web applications.


--------------------------------------------------------------------------------
kSSL

The Kilobyte SSL (or kSSL) is a client-side implementation of SSL version 3.0. It supports the most commonly used cipher suites, such as RSA_RC4_128_MD5 and RSA_RC4_40_MD5. Note that kSSL doesn't support client-side authentication, but as I mentioned earlier this is rarely used in e-commerce applications. For an overview of kSSL, please see Security in Wireless Internet using kSSL, and for a more detailed explanation please see kSSL: Experiments with Wireless Internet Security


--------------------------------------------------------------------------------
Programming with SSL

The MIDP 1.0 specification requires implementers to support the HTTP protocol. Support for all other protocols is optional. One implication is that support for socket or datagram connections is not required. The MIDP 1.0.3 Reference Implementation and the J2ME Wireless Toolkit (1.0.4 Beta was used in preparation of this article) does accept https:// URLs in addition to http:// URLs, however, relying on support provided by the kSSL. MIDP and toolkit support for HTTPS is very welcome, but note that you have only indirect access to HTTPS. At present, the kSSL APIs are intentionally hidden from developers because they have not yet been standardized in the Java Community Process.

Therefore, the easiest way to exploit HTTPS support in the J2ME Wireless Toolkit is to create an HTTPS URL object as follows:

String url = "https://myhost.com/somefile";HttpConnection c = (HttpConnection) Connector.open(url);

Example 1: HelloNet
Let's look at a full example of accessing an HTTPS site and retrieving information from it. The URL we will use is https://central.sun.net. If you specify this URL in an ordinary Web browser, you will see an advisory similar to Figure 1.


Figure 1: https://central.sun.net

If you get a security alert popup window like the one in Figure 2, the HTTPS server certificate was generated by an unknown certification authority, one that was not found among the certification authorities your browser keeps in its store. You have the option to view the certificate (check whether it is a proper certificate and discover who signed it), reject the certification, or install the certificate.



Figure 2: Server certificate issued by an unknown certification authority

If you install the certificate you will be able to see the page behind the secure connection, and future access to the same Web site will not cause the browser to issue a security alert. As an example, try to visit: https://www.jam.ca. If you have never visited this Web site before and you have never installed its certificate, you will see a security alert like the one in Figure 2.

This process works with wireless devices as well. If you try to open a connection to a secure Web site whose certificate was generated by a certification authority your device does not know, then (depending on how the application is written) you may be prompted to accept or reject the certificate, or you may encounter a bad-certificate exception. Each device that supports authentication in this manner maintains a keystore where it saves these certificates. Later in the article you will see how to add certificates to this store.

Back to the example. To open an HTTPS connection to https://central.sun.net, use the HttpConnection and Connector.open to establish a secure connection. Once a secure connection is established, use an input stream to read the contents of the default page. The HelloNet MIDlet in Code Sample 1 shows how:

Code Sample 1: HelloNet.java

import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;

public class HelloNet extends MIDlet implements
 CommandListener {;

   // User interface command to exit the current
   // application.
   private Command exitCommand  = new Command("Exit",
     Command.EXIT, 2);
   // User interface command to issue an HTTP GET
   // request.
   private Command getCommand = new Command("Get",
     Command.SCREEN, 1);

   /// The current display object.
   private Display display;
   // The url to GET from the 'net.
   private String url;

   /**
    * Initialize the MIDlet with a handle to the
    * current display.
    */
   public HelloNet() {;
       url = "https://127.0.0.1/hello.txt";
display = Display.getDisplay(this);
   };

   /**
    * This lifecycle method should return immediately
    * to keep the dispatcher
    * from hanging.
    */
   public void startApp() {;
showPrompt();
   };

   /**
    * Display the main screen.
    */
   void showPrompt() {;
       String s = "Press Get to fetch " + url;
       TextBox t = new TextBox("Http Result", s,
         s.length(), 0);
       t.addCommand(exitCommand);
       t.addCommand(getCommand);
       t.setCommandListener(this);
display.setCurrent(t);
   };

   /**
    * Read the content of the page.
    */
   private void readContents(String request) {;
StringBuffer b = new StringBuffer();
HttpConnection c = null;
       InputStream is = null;
TextBox t = null;
try {;
   int len = 0;
   int ch = 0;
           c = (HttpConnection)Connector.open(url);
           c.setRequestMethod(HttpConnection.GET);
   is = c.openInputStream();

           // length of content to be read.
           len = (int) c.getLength();

           if (len != -1) {;
             // Read exactly Content-Length bytes
             for(int i=0; i<len; i++) {;
               if((ch = is.read()) != -1) {;
                 b.append((char) ch);
               };
             };
           }; else {;
             // Read until connection is closed.
             while((ch = is.read()) != -1) {;
               len = is.available();
                 b.append((char) ch);
             };
           };

           t = new TextBox("Http Result", b.toString(),
             b.length(), 0);
}; catch (Exception e) {;
         e.printStackTrace();
         String s = e.toString();
         if(s != null) {;
           t = new TextBox("Http Error", s, s.length(),
             0);
         };

       }; finally {;
         if (is != null) {;
   try {;
is.close();
   }; catch (Exception ce) {; };
         };
         if (c != null) {;
   try {;
c.close();
   }; catch (Exception ce) {; };
         };
       };

       display.setCurrent(t);
   };

   /**
    * pauseApp signals the thread to stop by clearing
    * the thread field.
    * If stopped incorrectly, it will be restarted from
    * scratch later.
    */
   public void pauseApp() {;
   };

   /**
    * destroyApp must cleanup everything.  The thread
    * is signaled
    * to stop and no result is produced.
    * @param unconditional is a flag to indicate that
    * forced shutdown
    * is requested
    */
   public void destroyApp(boolean unconditional) {;
   };

   /**
    * commandAction responds to commands
    * @param c command to perform
    * @param s Screen displayable object
    */
   public void commandAction(Command c, Displayable s) {;
if (c == exitCommand) {;
   destroyApp(false);
   notifyDestroyed();
}; else if (c == getCommand) {;
   readContents(url);
};
   };
};



--------------------------------------------------------------------------------

Note: The IP address used here is 127.0.0.1, a loopback address. If the server and client are running on different machines across the network, use the server's IP address or symbolic name in the URLs.


--------------------------------------------------------------------------------

When you run the HelloNet MIDlet and activate it, you see output similar to Figure 3.


Figure 3: HelloNet midlet accessing https://central.sun.net
As you see, the HTML content was retrieved from https://central.sun.com and displayed as is.


--------------------------------------------------------------------------------

Note: Before the HTTPS connection is established between the device and https://central.sun.net, there is a handshake session. Essentially, the Web server sends its certificate to the device for authentication, and the two parties agree on a cipher suite to use. If the device recognizes the certification authority that issued the certificate and the two parties have enough encryption algorithms in common, then the connection is established. In the J2ME Wireless Toolkit, agreement of this kind is reached as follows: The toolkit is shipped with a keystore file that contains keys for a number of CAs. If a certificate was self-issued, or was issued by a CA that is not in the keystore, you can import it, using techniques described later in this article.


--------------------------------------------------------------------------------

Example 2: Unknown Certificates
Now let's look at an example of a bad certificate. Here, the client requests an HTTPS connection to https://www.javacourses.com. The request will trigger an exception because the certificate for this Web site was generated by Entrust, a CA not represented in the keystore of the J2ME Wireless Toolkit. To run this example, change the url in Code Sample 1 from https://central.sun.net to https://www.javacourses.com. Build, run, and activate the HelloNet MIDlet, and you will see output similar to Figure 4.


Figure 4: Certificate issued by an unknown certification authority
Later in this article you will learn how to import certificates to the J2ME Wireless Toolkit keystore.

Example 3: Creating New Certificates
In this example, you will use the Tomcat server as a secure server. First you need to configure Tomcat to handle HTTPS connections. The best way is to download and install Tomcat 4 and the J2SETM 1.4. To provide HTTPS connections Tomcat relies on the JavaTM Socket Secure Extension (JSSETM), a Java implementation of SSL and TLS. The JSSE is a core package of the J2SE 1.4.


For convenient review of later examples, let's assume you have installed Tomcat, J2SE, and J2ME in the root directory of Drive C on an MS-Windows platform:


--------------------------------------------------------------------------------

Assumptions

Tomcat 4 is installed at c:\tomcat
J2SE 1.4 is installed at c:\j2sdk1.4
J2ME Wireless Toolkit is installed at c:\wtk104

--------------------------------------------------------------------------------

Once you have downloaded and installed Tomcat 4 and J2SE 1.4 successfully, you can easily configure Tomcat to handle HTTPS connections by performing two steps. In the first step, you create one of two certificate keystores you'll use. The one you create here will be the source of certificates you import into the other keystore, the one in the mobile device.


Use the keytool utility to create a certificate keystore, by executing the following command:
keytool -genkey alias tomcat -keyalg RSA

The utility will ask you to enter some information. Make sure you enter the IP address or the hostname for the first entry (first and last name). When prompted for a password, use the default, which is changeit. If prompted for the password more than once, make sure you supply the same password each time.

The keytool will create a new file, named .keystore by default, in your home directory. You will need to know where this directory is when you import keys from this keystore into the one on the handheld device. If you don't know your home directory, you can find it easily. Just save the following snippet of code as homedir.java, compile it, and run it.

import java.io.*;
public class homedir {;
 public static void main(String argv[]) {;      
   System.out.println(System.getProperty("user.home"));
 };
};

When I ran this, the output was: c:\documents and settings\qmahmoud. When I looked in that directory I found my new .keystore.

In c:\tomcat\conf\server.xml remove the comment marks from  the SSL HTTP/1.1 Connector entry as follows:
 
<!-- Define an SSL HTTP/1.1 Connector on port 8443 -->
<Connector className="org.apache.catalina.connector.http.HttpConnector"
         port="443" minProcessors="5" maxProcessors="75"
         enableLookups="true"
         acceptCount="10" debug="0" scheme="https" secure="true">
   <Factory className="org.apache.catalina.net.SSLServerSocketFactory"
            clientAuth="false" protocol="TLS"/>
</Connector>

By default, the port number for Tomcat HTTPS is 8443. I have changed it to 443, the standard port number for HTTPS. Note, however, that you need special permissions to use a port number less than 1024.

Start Tomcat (or restart it, if it is already running). In your Web browser, enter the URL https://127.0.0.1 or https://127.0.0.1:443 (or https://127.0.0.1:8443 if you left the default port number intact). If all goes well, you should see the Tomcat homepage.


--------------------------------------------------------------------------------

Note: When you start Tomcat, it uses the new certificate you generated earlier with keytool. This certificate is self-issued, and thus not issued by a trusted certification authority, and your browser doesn't know about it and therefore doesn't trust it.  As a result, you will receive a security alert like the one in Figure 2 the first time you request your own URL. Just accept the certificate. You can trust it because you issued it yourself.


--------------------------------------------------------------------------------

Example 4: Importing Certificates
Now let's revise HelloNet MIDlet to request the URL https://127.0.0.1/hello.txt:

Using your favorite text editor, create a file containing the following text:
Hello there. SSL is working.Enjoy!
Save the file as c:\tomcat\webapps\root\hello.txt. To test it, request it from an ordinary browser using the URL https://127.0.0.1/hello.txt.

Change the url in Code Sample 1 from https://central.sun.net to https://127.0.0.1/hello.txt. Save the HelloNet MIDlet, build it, run it, and activate it.  
When you activate the MIDlet, you will encounter an exception that reports a bad certificate. Why? Well, the certificate for Tomcat was self-issued and therefore not trusted by the J2ME Wireless Toolkit.

Luckily, the J2ME Wireless Toolkit includes a tool called MEKeyTool (Mobile Equipment Key Tool), which is similar to J2SE's keytool. The purpose of this certificate-manager utility is to manage the public keys of certificate authorities.

MEKeyTool is packaged as a JAR file. To use it, you must change directories to c:\wtk104 and use this command:

jar -jar bin/MEKeyTool.jar <command>

You'll use the <command> argument to direct the utility to import, delete, or list public keys for certificates.

The default MEKeyTool keystore is c:\wtk104\appdb\_main.ks. You need to know this location because you will use it when deleting, listing, and importing keys. To list the keys in the default MEKeyTool keystore, use the command:

java -jar bin\MEKeyTool.jar -list

This command will display all the public keys for trusted certificates. Note that if you execute this command from any other directory you will need to use the -MEkeystore option and specify the full path to the MEKeyTool keystore.

To delete a key from the default keystore with the given owner, use the following command:

java -jar bin\MEKeyTool.jar -delete -owner <alias>

Finally, to import a public key into the default keystore from a keystore managed by keytool, use this command:

java -jar bin\MEKeyTool.jar -import -alias <alias> -keystore <keystore> -storepass <storepass>

For example, I used the following command to import the Tomcat public key into the MEKeyTool keystore:

java -jar bin\MEKeyTool.jar -import -alias tomcat -keystore "c:\documents and settings\qmahmoud\.keystore" -storepass changeit

If the command is successful, you see no output, but it's easy to see whether Tomcat's public key is now in the key list: just run the list command again.

Once the Tomcat public key has been imported into the MEKeyTool keystore, restart the HelloNet MIDlet and activate it. If all goes well, you will see the contents of hello.txt, as in Figure 5:


Figure 5: https://127.0.0.1/hello.txt
Example 5: Invoking a Servlet over HTTPS
This final example shows you how to invoke a servlet over an HTTPS connection. Assume that we have the following servlet:

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class LoginServlet extends HttpServlet {;   public void doGet(HttpServletRequest request,                      HttpServletResponse response)        throws IOException, ServletException    {;        response.setContentType("text/plain");        PrintWriter out = response.getWriter();        String userid = request.getParameter("userid");        String password = request.getParameter("password");        if(userid.equals("qm") && password.equals("hi")) {;          out.println("Login successful.");        }; else {;          out.println("Login failed.");        };    };};
The LoginServlet handles GET requests. It expects two parameters: the userid and the password. If the user provides the correct values, namely qm for userid and hi for password, the LoginServlet sends the message Login successful., otherwise Login failed.


Never giveup. Thanks the world.
原文地址:https://www.cnblogs.com/cnsoft/p/60233.html