FileDocCategorySizeDatePackage
Protocol.javaAPI DocJ2ME MIDP 2.013639Thu Nov 07 12:02:22 GMT 2002com.sun.midp.io.j2me.https

Protocol

public class Protocol extends com.sun.midp.io.j2me.http.Protocol implements HttpsConnection
This class implements the necessary functionality for an HTTPS connection. With support for HTTPS tunneling.

Handshake error codes at the beginning of IOException messages:

(1) certificate is expired

(2) certificate is not yet valid

(3) certificate failed signature verification

(4) certificate was signed using an unsupported algorithm

(5) certificate was issued by an unrecognized certificate authority

(6) certificate does not contain the correct site name

(7) certificate chain exceeds the length allowed

(8) certificate does not contain a signature

(9) version 3 certificate has unrecognized critical extensions

(10) version 3 certificate has an inappropriate keyUsage or extendedKeyUsage extension

(11) certificate in the a chain was not issued by the next authority in the chain

(12) trusted certificate authority's public key is expired

Fields Summary
private static final String
COMMON_NAME_LABEL
Common name label.
private static final int
COMMON_NAME_LABEL_LENGTH
Common name label length.
private static SecurityToken
classSecurityToken
This class has a different security domain than the MIDlet suite
private Properties
proxyHeaders
collection of "Proxy-" headers as name/value pairs
private SSLStreamConnection
sslConnection
Underlying SSL connection.
Constructors Summary
public Protocol()
Create a new instance of this class. Override the some of the values in our super class.


                          
      
        protocol = "https";
        default_port = 443; // 443 is the default port for HTTPS

        requiredPermission = Permissions.HTTPS;
    
Methods Summary
private static booleancheckSiteName(java.lang.String siteName, java.lang.String certName)
Check to see if the site name given by the user matches the site name of subject in the certificate. The method supports the wild card character for the machine name if a domain name is included after it.

param
siteName site name the user provided
param
certName site name of the subject from a certificate
return
true if the common name checks out, else false

        int startOfDomain;
        int domainLength;

        if (certName == null) {
            return false;
        }

        // try the easy way first, ignoring case
        if ((siteName.length() == certName.length()) &&
            siteName.regionMatches(true, 0, certName, 0,
                                   certName.length())) {
            return true;
        }

        if (!certName.startsWith("*.")) {
            // not a wild card, done
            return false;
        }

        startOfDomain = siteName.indexOf('.");
        if (startOfDomain == -1) {
            // no domain name
            return false;
        }

        // skip past the '.'
        startOfDomain++;

        domainLength = siteName.length() - startOfDomain;
        if ((certName.length() - 2) != domainLength) {
            return false;
        }

        // compare the just the domain names, ignoring case
        if (siteName.regionMatches(true, startOfDomain, certName, 2,
                                   domainLength)) {
            return true;
        }

        return false;
    
protected StreamConnectionconnect()
Connect to the underlying secure socket transport. Perform the SSL handshake and then proceded to the underlying HTTP protocol connect semantics.

return
SSL/TCP stream connection
exception
IOException is thrown if the connection cannot be opened

        String httpsTunnel;
        com.sun.midp.io.j2me.socket.Protocol tcpConnection;
        OutputStream tcpOutputStream;
        InputStream tcpInputStream;
        X509Certificate serverCert;

        verifyPermissionCheck();

        /*
         * To save memory for applications the do not use HTTPS,
         * the public keys of the certificate authorities may not
         * have been loaded yet.
         */
        WebPublicKeyStore.loadCertificateAuthorities();

        // Open socket connection
        tcpConnection =
            new com.sun.midp.io.j2me.socket.Protocol();

        // check to see if a protocol is specified for the tunnel
        httpsTunnel = Configuration.getProperty("com.sun.midp.io.http.proxy");
        if (httpsTunnel != null) {
            // Make the connection to the ssl tunnel
            tcpConnection.openPrim(classSecurityToken, "//" + httpsTunnel);

            // Do not delay request since this delays the response.
            tcpConnection.setSocketOption(SocketConnection.DELAY, 0);

            tcpOutputStream = tcpConnection.openOutputStream();
            tcpInputStream = tcpConnection.openInputStream();
            
            // Do the handshake with the ssl tunnel
            try {
                doTunnelHandshake(tcpOutputStream, tcpInputStream);
            } catch (IOException ioe) {
                String temp = ioe.getMessage();

                tcpConnection.close();
                tcpOutputStream.close();
                tcpInputStream.close();

                if (temp.indexOf(" 500 ") > -1) {
                    throw new ConnectionNotFoundException(temp);
                }

                throw ioe;
            }    
        } else {
            tcpConnection.openPrim(classSecurityToken, "//" + hostAndPort);

            // Do not delay request since this delays the response.
            tcpConnection.setSocketOption(SocketConnection.DELAY, 0);

            tcpOutputStream = tcpConnection.openOutputStream();
            tcpInputStream = tcpConnection.openInputStream();
        }

        tcpConnection.close();

        try {
            // Get the SSLStreamConnection
            sslConnection = new SSLStreamConnection(url.host, url.port,
                                tcpInputStream, tcpOutputStream);
        } catch (Exception e) {
            try {
                tcpInputStream.close();
            } finally {
                try {
                    tcpOutputStream.close();
                } finally {
                    if (e instanceof IOException) {
                        throw (IOException)e;
                    } else {
                        throw (RuntimeException)e;
                    }
                }
            }
        }

        try {
            serverCert = sslConnection.getServerCertificate();

            /*
             * if the subject alternate name is a DNS name,
             * then use that instead of the common name for a
             * site name match
             */
            if (serverCert.getSubjectAltNameType() ==
                X509Certificate.TYPE_DNS_NAME) {
                if (!checkSiteName(url.host,
                        (String)serverCert.getSubjectAltName())) {
                    throw new CertificateException(
                        "Subject alternative name did not match site name",
                        serverCert, CertificateException.SITENAME_MISMATCH);
                }
            } else {
                String cname = getCommonName(serverCert.getSubject());
                if (cname == null) {
                    throw new CertificateException(
                        "Common name missing from subject name",
                        serverCert, CertificateException.SITENAME_MISMATCH);
                }
                
                if (!checkSiteName(url.host, cname)) {
                    throw new CertificateException(serverCert,
                        CertificateException.SITENAME_MISMATCH);
                }
            }

            return sslConnection;
        } catch (Exception e) {
            try {
                sslConnection.close();
            } finally {
                if (e instanceof IOException) {
                    throw (IOException)e;
                } else {
                    throw (RuntimeException)e;
                }
            }
        }
    
protected voiddisconnect(StreamConnection connection, java.io.InputStream inputStream, java.io.OutputStream outputStream)
disconnect the current connection.

param
connection connection return from {@link #connect()}
param
inputStream input stream opened from connection
param
outputStream output stream opened from connection
exception
IOException if an I/O error occurs while the connection is terminated.

        try {
            try {
                inputStream.close();
            } finally {
                try {
                    outputStream.close();
                } finally {
                    connection.close();
                }
            }
        } catch (IOException e) {
        } catch (NullPointerException e) {
        }
    
private static java.lang.StringgetCommonName(java.lang.String name)
Parse the common name out of a distinguished name.

param
name distinguished name
return
common name attribute without the label

        int start;
        int end;

        if (name == null) {
            return null;
        }

        /* The common name starts with "CN=" label */
        start = name.indexOf(COMMON_NAME_LABEL);
        if (start < 0) {
            return null;
        }

        start += COMMON_NAME_LABEL_LENGTH;
        end = name.indexOf(';", start);
        if (end < 0) {
            end = name.length();
        }

        return name.substring(start, end);
    
public java.lang.StringgetRequestProperty(java.lang.String key)
Get the request header value for the named property.

param
key property name of specific HTTP 1.1 header field
return
value of the named property, if found, null otherwise.

        /* https handles the proxy fields in a different way */
        if (key.startsWith("Proxy-")) {
            return proxyHeaders.getProperty(key);
        }

        return super.getRequestProperty(key);
    
public SecurityInfogetSecurityInfo()
Return the security information associated with this connection. If the connection is still in Setup state then the connection is initiated to establish the secure connection to the server. The method returns when the connection is established and the Certificate supplied by the server has been validated. The SecurityInfo is only returned if the connection has been successfully made to the server.

return
the security information associated with this open connection.
exception
CertificateException if the Certificate supplied by the server cannot be validated. The CertificateException will contain the information about the error and indicate the certificate in the validation chain with the error.
exception
IOException if an arbitrary connection failure occurs

        ensureOpen();

        sendRequest();

        if (sslConnection == null) {
            /*
             * This is a persistent connection so the connect method did 
             * not get called, so the stream connection of HTTP class
             * will be a SSL connection. Get the info from that.
             */
            StreamConnection sc =
                ((StreamConnectionElement)getStreamConnection()).
                    getBaseConnection();

            return ((SSLStreamConnection)sc).getSecurityInfo();
        }

        return sslConnection.getSecurityInfo();
    
public static voidinitSecurityToken(SecurityToken token)
Initializes the security token for this class, so it can perform actions that a normal MIDlet Suite cannot.

param
token security token for this class.

    
                                  
         
	if (classSecurityToken != null) {
	    return;
	}
	
	classSecurityToken = token;
    
protected voidsetRequestField(java.lang.String key, java.lang.String value)
Add the named field to the list of request fields.

param
key key for the request header field.
param
value the value for the request header field.

        /* https handles the proxy fields in a different way */
        if (key.startsWith("Proxy-")) {
            proxyHeaders.setProperty(key, value);
            return;
        }

        super.setRequestField(key, value);