2493 lines · 91.5 KB · Java
RawDownload
                    if (needAppData || connectionState != cs_DATA) {                        continue;                    }                    break;                 case Record.ct_application_data:                    // Pass this right back up to the application.                    if (connectionState != cs_DATA                            && connectionState != cs_RENEGOTIATE                            && connectionState != cs_SENT_CLOSE) {                        throw new SSLProtocolException(                            "Data received in non-data state: " +                            connectionState);                    }                    if (expectingFinished) {                        throw new SSLProtocolException                                ("Expecting finished message, received data");                    }                    if (!needAppData) {                        throw new SSLException("Discarding app data");                    }                     r.setAppDataValid(true);                    break;                 case Record.ct_alert:                    recvAlert(r);                    continue;                 case Record.ct_change_cipher_spec:                    if ((connectionState != cs_HANDSHAKE                                && connectionState != cs_RENEGOTIATE)                            || r.available() != 1                            || r.read() != 1) {                        fatal(Alerts.alert_unexpected_message,                            "illegal change cipher spec msg, state = "                            + connectionState);                    }                     //                    // The first message after a change_cipher_spec                    // record MUST be a "Finished" handshake record,                    // else it's a protocol violation.  We force this                    // to be checked by a minor tweak to the state                    // machine.                    //                    changeReadCiphers();                    // next message MUST be a finished message                    expectingFinished = true;                    continue;                 default:                    //                    // TLS requires that unrecognized records be ignored.                    //                    if (debug != null && Debug.isOn("ssl")) {                        System.out.println(threadName() +                            ", Received record type: "                            + r.contentType());                    }                    continue;              } // switch               /*               * Check the sequence number state               *               * Note that in order to maintain the connection I/O               * properly, we check the sequence number after the last               * record reading process. As we request renegotiation               * or close the connection for wrapped sequence number               * when there is enough sequence number space left to               * handle a few more records, so the sequence number               * of the last record cannot be wrapped.               */              if (connectionState < cs_ERROR) {                  checkSequenceNumber(readMAC, r.contentType());              }               return;            } // synchronized (this)        }         //        // couldn't read, due to some kind of error        //        r.close();        return;      }  // synchronized (readLock)    }     /**     * Check the sequence number state     *     * RFC 4346 states that, "Sequence numbers are of type uint64 and     * may not exceed 2^64-1.  Sequence numbers do not wrap. If a TLS     * implementation would need to wrap a sequence number, it must     * renegotiate instead."     */    private void checkSequenceNumber(MAC mac, byte type)            throws IOException {         /*         * Don't bother to check the sequence number for error or         * closed connections, or NULL MAC.         */        if (connectionState >= cs_ERROR || mac == MAC.NULL) {            return;        }         /*         * Conservatively, close the connection immediately when the         * sequence number is close to overflow         */        if (mac.seqNumOverflow()) {            /*             * TLS protocols do not define a error alert for sequence             * number overflow. We use handshake_failure error alert             * for handshaking and bad_record_mac for other records.             */            if (debug != null && Debug.isOn("ssl")) {                System.out.println(threadName() +                    ", sequence number extremely close to overflow " +                    "(2^64-1 packets). Closing connection.");             }             fatal(Alerts.alert_handshake_failure, "sequence number overflow");        }         /*         * Ask for renegotiation when need to renew sequence number.         *         * Don't bother to kickstart the renegotiation when the local is         * asking for it.         */        if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {            if (debug != null && Debug.isOn("ssl")) {                System.out.println(threadName() + ", request renegotiation " +                        "to avoid sequence number overflow");            }             startHandshake();        }    }     //    // HANDSHAKE RELATED CODE    //     /**     * Return the AppInputStream. For use by Handshaker only.     */    AppInputStream getAppInputStream() {        return input;    }     /**     * Return the AppOutputStream. For use by Handshaker only.     */    AppOutputStream getAppOutputStream() {        return output;    }     /**     * Initialize the handshaker object. This means:     *     *  . if a handshake is already in progress (state is cs_HANDSHAKE     *    or cs_RENEGOTIATE), do nothing and return     *     *  . if the socket is already closed, throw an Exception (internal error)     *     *  . otherwise (cs_START or cs_DATA), create the appropriate handshaker     *    object, and advance the connection state (to cs_HANDSHAKE or     *    cs_RENEGOTIATE, respectively).     *     * This method is called right after a new socket is created, when     * starting renegotiation, or when changing client/ server mode of the     * socket.     */    private void initHandshaker() {        switch (connectionState) {         //        // Starting a new handshake.        //        case cs_START:        case cs_DATA:            break;         //        // We're already in the middle of a handshake.        //        case cs_HANDSHAKE:        case cs_RENEGOTIATE:            return;         //        // Anyone allowed to call this routine is required to        // do so ONLY if the connection state is reasonable...        //        default:            throw new IllegalStateException("Internal error");        }         // state is either cs_START or cs_DATA        if (connectionState == cs_START) {            connectionState = cs_HANDSHAKE;        } else { // cs_DATA            connectionState = cs_RENEGOTIATE;        }        if (roleIsServer) {            handshaker = new ServerHandshaker(this, sslContext,                    enabledProtocols, doClientAuth,                    protocolVersion, connectionState == cs_HANDSHAKE,                    secureRenegotiation, clientVerifyData, serverVerifyData);        } else {            handshaker = new ClientHandshaker(this, sslContext,                    enabledProtocols,                    protocolVersion, connectionState == cs_HANDSHAKE,                    secureRenegotiation, clientVerifyData, serverVerifyData);        }        handshaker.setEnabledCipherSuites(enabledCipherSuites);        handshaker.setEnableSessionCreation(enableSessionCreation);    }     /**     * Synchronously perform the initial handshake.     *     * If the handshake is already in progress, this method blocks until it     * is completed. If the initial handshake has already been completed,     * it returns immediately.     */    private void performInitialHandshake() throws IOException {        // use handshakeLock and the state check to make sure only        // one thread performs the handshake        synchronized (handshakeLock) {            if (getConnectionState() == cs_HANDSHAKE) {                kickstartHandshake();                 /*                 * All initial handshaking goes through this                 * InputRecord until we have a valid SSL connection.                 * Once initial handshaking is finished, AppInputStream's                 * InputRecord can handle any future renegotiation.                 *                 * Keep this local so that it goes out of scope and is                 * eventually GC'd.                 */                if (inrec == null) {                    inrec = new InputRecord();                     /*                     * Grab the characteristics already assigned to                     * AppInputStream's InputRecord.  Enable checking for                     * SSLv2 hellos on this first handshake.                     */                    inrec.setHandshakeHash(input.r.getHandshakeHash());                    inrec.setHelloVersion(input.r.getHelloVersion());                    inrec.enableFormatChecks();                }                 readRecord(inrec, false);                inrec = null;            }        }    }     /**     * Starts an SSL handshake on this connection.     */    public void startHandshake() throws IOException {        // start an ssl handshake that could be resumed from timeout exception        startHandshake(true);    }     /**     * Starts an ssl handshake on this connection.     *     * @param resumable indicates the handshake process is resumable from a     *          certain exception. If <code>resumable</code>, the socket will     *          be reserved for exceptions like timeout; otherwise, the socket     *          will be closed, no further communications could be done.     */    private void startHandshake(boolean resumable) throws IOException {        checkWrite();        try {            if (getConnectionState() == cs_HANDSHAKE) {                // do initial handshake                performInitialHandshake();            } else {                // start renegotiation                kickstartHandshake();            }        } catch (Exception e) {            // shutdown and rethrow (wrapped) exception as appropriate            handleException(e, resumable);        }    }     /**     * Kickstart the handshake if it is not already in progress.     * This means:     *     *  . if handshaking is already underway, do nothing and return     *     *  . if the socket is not connected or already closed, throw an     *    Exception.     *     *  . otherwise, call initHandshake() to initialize the handshaker     *    object and progress the state. Then, send the initial     *    handshaking message if appropriate (always on clients and     *    on servers when renegotiating).     */    private synchronized void kickstartHandshake() throws IOException {         switch (connectionState) {         case cs_HANDSHAKE:            // handshaker already setup, proceed            break;         case cs_DATA:            if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) {                throw new SSLHandshakeException(                        "Insecure renegotiation is not allowed");            }             if (!secureRenegotiation) {                if (debug != null && Debug.isOn("handshake")) {                    System.out.println(                        "Warning: Using insecure renegotiation");                }            }             // initialize the handshaker, move to cs_RENEGOTIATE            initHandshaker();            break;         case cs_RENEGOTIATE:            // handshaking already in progress, return            return;         /*         * The only way to get a socket in the state is when         * you have an unconnected socket.         */        case cs_START:            throw new SocketException(                "handshaking attempted on unconnected socket");         default:            throw new SocketException("connection is closed");        }         //        // Kickstart handshake state machine if we need to ...        //        // Note that handshaker.kickstart() writes the message        // to its HandshakeOutStream, which calls back into        // SSLSocketImpl.writeRecord() to send it.        //        if (!handshaker.activated()) {             // prior to handshaking, activate the handshake            if (connectionState == cs_RENEGOTIATE) {                // don't use SSLv2Hello when renegotiating                handshaker.activate(protocolVersion);            } else {                handshaker.activate(null);            }             if (handshaker instanceof ClientHandshaker) {                // send client hello                handshaker.kickstart();            } else {                if (connectionState == cs_HANDSHAKE) {                    // initial handshake, no kickstart message to send                } else {                    // we want to renegotiate, send hello request                    handshaker.kickstart();                    // hello request is not included in the handshake                    // hashes, reset them                    handshaker.handshakeHash.reset();                }            }        }    }     //    // CLOSURE RELATED CALLS    //     /**     * Return whether the socket has been explicitly closed by the application.     */    public boolean isClosed() {        return getConnectionState() == cs_APP_CLOSED;    }     /**     * Return whether we have reached end-of-file.     *     * If the socket is not connected, has been shutdown because of an error     * or has been closed, throw an Exception.     */    boolean checkEOF() throws IOException {        switch (getConnectionState()) {        case cs_START:            throw new SocketException("Socket is not connected");         case cs_HANDSHAKE:        case cs_DATA:        case cs_RENEGOTIATE:        case cs_SENT_CLOSE:            return false;         case cs_APP_CLOSED:            throw new SocketException("Socket is closed");         case cs_ERROR:        case cs_CLOSED:        default:            // either closed because of error, or normal EOF            if (closeReason == null) {                return true;            }            IOException e = new SSLException                        ("Connection has been shutdown: " + closeReason);            e.initCause(closeReason);            throw e;         }    }     /**     * Check if we can write data to this socket. If not, throw an IOException.     */    void checkWrite() throws IOException {        if (checkEOF() || (getConnectionState() == cs_SENT_CLOSE)) {            // we are at EOF, write must throw Exception            throw new SocketException("Connection closed by remote host");        }    }     protected void closeSocket() throws IOException {         if ((debug != null) && Debug.isOn("ssl")) {            System.out.println(threadName() + ", called closeSocket()");        }        if (self == this) {            super.close();        } else {            self.close();        }    }     private void closeSocket(boolean selfInitiated) throws IOException {        if ((debug != null) && Debug.isOn("ssl")) {            System.out.println(threadName() + ", called closeSocket(selfInitiated)");        }        if (self == this) {            super.close();        } else if (autoClose) {            self.close();        } else if (selfInitiated) {            // layered && non-autoclose            // read close_notify alert to clear input stream            waitForClose(false);        }    }     /*     * Closing the connection is tricky ... we can't officially close the     * connection until we know the other end is ready to go away too,     * and if ever the connection gets aborted we must forget session     * state (it becomes invalid).     */     /**     * Closes the SSL connection.  SSL includes an application level     * shutdown handshake; you should close SSL sockets explicitly     * rather than leaving it for finalization, so that your remote     * peer does not experience a protocol error.     */    public void close() throws IOException {        if ((debug != null) && Debug.isOn("ssl")) {            System.out.println(threadName() + ", called close()");        }        closeInternal(true);  // caller is initiating close        setConnectionState(cs_APP_CLOSED);    }     /**     * Don't synchronize the whole method because waitForClose()     * (which calls readRecord()) might be called.     *     * @param selfInitiated Indicates which party initiated the close.     * If selfInitiated, this side is initiating a close; for layered and     * non-autoclose socket, wait for close_notify response.     * If !selfInitiated, peer sent close_notify; we reciprocate but     * no need to wait for response.

Lines 1001–1500 of 2493. Previous lines