SUN官方的资料

源代码在线查看: protocol.java

软件大小: 7468 K
上传用户: snowpilce
关键词: SUN
下载地址: 免注册下载 普通下载 VIP

相关代码

				/*				 * @(#)Protocol.java	1.25 02/09/20 @(#)				 *				 * Copyright (c) 2001-2002 Sun Microsystems, Inc.  All rights reserved.				 * PROPRIETARY/CONFIDENTIAL				 * Use is subject to license terms.				 */								package com.sun.midp.io.j2me.https;								import java.util.Hashtable;				import java.util.Enumeration;								import java.io.IOException;				import java.io.InputStream;				import java.io.OutputStream;								import javax.microedition.io.*;								import javax.microedition.pki.*;								import com.sun.midp.ssl.*;								import com.sun.midp.main.Configuration;								import com.sun.midp.io.*;								import com.sun.midp.io.j2me.http.*;								import com.sun.midp.publickeystore.WebPublicKeyStore;								import com.sun.midp.security.*;								/**				 * 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				 * 				 */				public class Protocol extends com.sun.midp.io.j2me.http.Protocol				    implements HttpsConnection {								    /** Common name label. */				    private static final String COMMON_NAME_LABEL = "CN=";								    /** Common name label length. */				    private static final int COMMON_NAME_LABEL_LENGTH =				        COMMON_NAME_LABEL.length();								    /** This class has a different security domain than the MIDlet suite */				    private static SecurityToken classSecurityToken;				    				    /**				     * 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.				     */				    public static void initSecurityToken(SecurityToken token) {					if (classSecurityToken != null) {					    return;					}										classSecurityToken = token;				    }								    /**				     * Parse the common name out of a distinguished name.				     *				     * @param name distinguished name				     *				     * @return common name attribute without the label				     */				    private static String getCommonName(String name) {				        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);				    }								    /**				     * 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				     */				    private static boolean checkSiteName(String siteName, String certName) {				        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;				    }								    /** collection of "Proxy-" headers as name/value pairs */				    private Properties proxyHeaders = new Properties();								    /** Underlying SSL connection. */				    private SSLStreamConnection sslConnection;								    /**				     * Create a new instance of this class. Override the some of the values				     * in our super class.				     */				    public Protocol() {				        protocol = "https";				        default_port = 443; // 443 is the default port for HTTPS								        requiredPermission = Permissions.HTTPS;				    }								    /** 				     * 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.				     */				    public String getRequestProperty(String key) {				        /* https handles the proxy fields in a different way */				        if (key.startsWith("Proxy-")) {				            return proxyHeaders.getProperty(key);				        }								        return super.getRequestProperty(key);				    }								    /**				     * 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.				     */				    protected void setRequestField(String key, String value) {				        /* https handles the proxy fields in a different way */				        if (key.startsWith("Proxy-")) {				            proxyHeaders.setProperty(key, value);				            return;				        }								        super.setRequestField(key, value);				    }								    /**				     * 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				     */				    protected StreamConnection connect() throws IOException {				        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;				                }				            }				        }				    }								    /**				     * 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.				     */				    protected void disconnect(StreamConnection connection,				           InputStream inputStream, OutputStream outputStream) 					throws IOException {				        try {				            try {				                inputStream.close();				            } finally {				                try {				                    outputStream.close();				                } finally {				                    connection.close();				                }				            }				        } catch (IOException e) {				        } catch (NullPointerException e) {				        }				    }								    /**				     * 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				     */				    public SecurityInfo getSecurityInfo() throws IOException {				        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();				    }				}							

相关资源