1386 lines · 48.9 KB · Java
RawDownload
     /**     * Set cipherSuite and keyExchange to the given CipherSuite.     * Does not perform any verification that this is a valid selection,     * this must be done before calling this method.     */    void setCipherSuite(CipherSuite s) {        this.cipherSuite = s;        this.keyExchange = s.keyExchange;    }     /**     * Check if the given ciphersuite is enabled and available.     * Does not check if the required server certificates are available.     */    boolean isNegotiable(CipherSuite s) {        if (activeCipherSuites == null) {            activeCipherSuites = getActiveCipherSuites();        }         return activeCipherSuites.contains(s) && s.isNegotiable();    }     /**     * Check if the given protocol version is enabled and available.     */    boolean isNegotiable(ProtocolVersion protocolVersion) {        if (activeProtocols == null) {            activeProtocols = getActiveProtocols();        }         return activeProtocols.contains(protocolVersion);    }     /**     * Select a protocol version from the list. Called from     * ServerHandshaker to negotiate protocol version.     *     * Return the lower of the protocol version suggested in the     * clien hello and the highest supported by the server.     */    ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {        if (activeProtocols == null) {            activeProtocols = getActiveProtocols();        }         return activeProtocols.selectProtocolVersion(protocolVersion);    }     /**     * Get the active cipher suites.     *     * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,     * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT     * negotiate these cipher suites in TLS 1.1 or later mode.     *     * Therefore, when the active protocols only include TLS 1.1 or later,     * the client cannot request to negotiate those obsoleted cipher     * suites.  That is, the obsoleted suites should not be included in the     * client hello. So we need to create a subset of the enabled cipher     * suites, the active cipher suites, which does not contain obsoleted     * cipher suites of the minimum active protocol.     *     * Return empty list instead of null if no active cipher suites.     */    CipherSuiteList getActiveCipherSuites() {        if (activeCipherSuites == null) {            if (activeProtocols == null) {                activeProtocols = getActiveProtocols();            }             ArrayList<CipherSuite> suites = new ArrayList<>();            if (!(activeProtocols.collection().isEmpty()) &&                    activeProtocols.min.v != ProtocolVersion.NONE.v) {                for (CipherSuite suite : enabledCipherSuites.collection()) {                    if (suite.obsoleted > activeProtocols.min.v &&                            suite.supported <= activeProtocols.max.v) {                        if (algorithmConstraints.permits(                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),                                suite.name, null)) {                            suites.add(suite);                        }                    } else if (debug != null && Debug.isOn("verbose")) {                        if (suite.obsoleted <= activeProtocols.min.v) {                            System.out.println(                                "Ignoring obsoleted cipher suite: " + suite);                        } else {                            System.out.println(                                "Ignoring unsupported cipher suite: " + suite);                        }                    }                }            }            activeCipherSuites = new CipherSuiteList(suites);        }         return activeCipherSuites;    }     /*     * Get the active protocol versions.     *     * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,     * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT     * negotiate these cipher suites in TLS 1.1 or later mode.     *     * For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the     * only enabled cipher suite, the client cannot request TLS 1.1 or     * later, even though TLS 1.1 or later is enabled.  We need to create a     * subset of the enabled protocols, called the active protocols, which     * contains protocols appropriate to the list of enabled Ciphersuites.     *     * Return empty list instead of null if no active protocol versions.     */    ProtocolList getActiveProtocols() {        if (activeProtocols == null) {            ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);            for (ProtocolVersion protocol : enabledProtocols.collection()) {                boolean found = false;                for (CipherSuite suite : enabledCipherSuites.collection()) {                    if (suite.isAvailable() && suite.obsoleted > protocol.v &&                                               suite.supported <= protocol.v) {                        if (algorithmConstraints.permits(                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),                                suite.name, null)) {                            protocols.add(protocol);                            found = true;                            break;                        } else if (debug != null && Debug.isOn("verbose")) {                            System.out.println(                                "Ignoring disabled cipher suite: " + suite +                                 " for " + protocol);                        }                    } else if (debug != null && Debug.isOn("verbose")) {                        System.out.println(                            "Ignoring unsupported cipher suite: " + suite +                                 " for " + protocol);                    }                }                if (!found && (debug != null) && Debug.isOn("handshake")) {                    System.out.println(                        "No available cipher suite for " + protocol);                }            }            activeProtocols = new ProtocolList(protocols);        }         return activeProtocols;    }     /**     * As long as handshaking has not activated, we can     * change whether session creations are allowed.     *     * Callers should do their own checking if handshaking     * has activated.     */    void setEnableSessionCreation(boolean newSessions) {        enableNewSession = newSessions;    }     /**     * Create a new read cipher and return it to caller.     */    CipherBox newReadCipher() throws NoSuchAlgorithmException {        BulkCipher cipher = cipherSuite.cipher;        CipherBox box;        if (isClient) {            box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,                                   sslContext.getSecureRandom(), false);            svrWriteKey = null;            svrWriteIV = null;        } else {            box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,                                   sslContext.getSecureRandom(), false);            clntWriteKey = null;            clntWriteIV = null;        }        return box;    }     /**     * Create a new write cipher and return it to caller.     */    CipherBox newWriteCipher() throws NoSuchAlgorithmException {        BulkCipher cipher = cipherSuite.cipher;        CipherBox box;        if (isClient) {            box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,                                   sslContext.getSecureRandom(), true);            clntWriteKey = null;            clntWriteIV = null;        } else {            box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,                                   sslContext.getSecureRandom(), true);            svrWriteKey = null;            svrWriteIV = null;        }        return box;    }     /**     * Create a new read MAC and return it to caller.     */    MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException {        MacAlg macAlg = cipherSuite.macAlg;        MAC mac;        if (isClient) {            mac = macAlg.newMac(protocolVersion, svrMacSecret);            svrMacSecret = null;        } else {            mac = macAlg.newMac(protocolVersion, clntMacSecret);            clntMacSecret = null;        }        return mac;    }     /**     * Create a new write MAC and return it to caller.     */    MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException {        MacAlg macAlg = cipherSuite.macAlg;        MAC mac;        if (isClient) {            mac = macAlg.newMac(protocolVersion, clntMacSecret);            clntMacSecret = null;        } else {            mac = macAlg.newMac(protocolVersion, svrMacSecret);            svrMacSecret = null;        }        return mac;    }     /*     * Returns true iff the handshake sequence is done, so that     * this freshly created session can become the current one.     */    boolean isDone() {        return state == HandshakeMessage.ht_finished;    }      /*     * Returns the session which was created through this     * handshake sequence ... should be called after isDone()     * returns true.     */    SSLSessionImpl getSession() {        return session;    }     /*     * Set the handshake session     */    void setHandshakeSessionSE(SSLSessionImpl handshakeSession) {        if (conn != null) {            conn.setHandshakeSession(handshakeSession);        } else {            engine.setHandshakeSession(handshakeSession);        }    }     /*     * Returns true if renegotiation is in use for this connection.     */    boolean isSecureRenegotiation() {        return secureRenegotiation;    }     /*     * Returns the verify_data from the Finished message sent by the client.     */    byte[] getClientVerifyData() {        return clientVerifyData;    }     /*     * Returns the verify_data from the Finished message sent by the server.     */    byte[] getServerVerifyData() {        return serverVerifyData;    }     /*     * This routine is fed SSL handshake records when they become available,     * and processes messages found therein.     */    void process_record(InputRecord r, boolean expectingFinished)            throws IOException {         checkThrown();         /*         * Store the incoming handshake data, then see if we can         * now process any completed handshake messages         */        input.incomingRecord(r);         /*         * We don't need to create a separate delegatable task         * for finished messages.         */        if ((conn != null) || expectingFinished) {            processLoop();        } else {            delegateTask(new PrivilegedExceptionAction<Void>() {                public Void run() throws Exception {                    processLoop();                    return null;                }            });        }    }     /*     * On input, we hash messages one at a time since servers may need     * to access an intermediate hash to validate a CertificateVerify     * message.     *     * Note that many handshake messages can come in one record (and often     * do, to reduce network resource utilization), and one message can also     * require multiple records (e.g. very large Certificate messages).     */    void processLoop() throws IOException {         // need to read off 4 bytes at least to get the handshake        // message type and length.        while (input.available() >= 4) {            byte messageType;            int messageLen;             /*             * See if we can read the handshake message header, and             * then the entire handshake message.  If not, wait till             * we can read and process an entire message.             */            input.mark(4);             messageType = (byte)input.getInt8();            messageLen = input.getInt24();             if (input.available() < messageLen) {                input.reset();                return;            }             /*             * Process the messsage.  We require             * that processMessage() consumes the entire message.  In             * lieu of explicit error checks (how?!) we assume that the             * data will look like garbage on encoding/processing errors,             * and that other protocol code will detect such errors.             *             * Note that digesting is normally deferred till after the             * message has been processed, though to process at least the             * client's Finished message (i.e. send the server's) we need             * to acccelerate that digesting.             *             * Also, note that hello request messages are never hashed;             * that includes the hello request header, too.             */            if (messageType == HandshakeMessage.ht_hello_request) {                input.reset();                processMessage(messageType, messageLen);                input.ignore(4 + messageLen);            } else {                input.mark(messageLen);                processMessage(messageType, messageLen);                input.digestNow();            }        }    }      /**     * Returns true iff the handshaker has been activated.     *     * In activated state, the handshaker may not send any messages out.     */    boolean activated() {        return state >= -1;    }     /**     * Returns true iff the handshaker has sent any messages.     */    boolean started() {        return state >= 0;  // 0: HandshakeMessage.ht_hello_request                            // 1: HandshakeMessage.ht_client_hello    }      /*     * Used to kickstart the negotiation ... either writing a     * ClientHello or a HelloRequest as appropriate, whichever     * the subclass returns.  NOP if handshaking's already started.     */    void kickstart() throws IOException {        if (state >= 0) {            return;        }         HandshakeMessage m = getKickstartMessage();         if (debug != null && Debug.isOn("handshake")) {            m.print(System.out);        }        m.write(output);        output.flush();         state = m.messageType();    }     /**     * Both client and server modes can start handshaking; but the     * message they send to do so is different.     */    abstract HandshakeMessage getKickstartMessage() throws SSLException;     /*     * Client and Server side protocols are each driven though this     * call, which processes a single message and drives the appropriate     * side of the protocol state machine (depending on the subclass).     */    abstract void processMessage(byte messageType, int messageLen)        throws IOException;     /*     * Most alerts in the protocol relate to handshaking problems.     * Alerts are detected as the connection reads data.     */    abstract void handshakeAlert(byte description) throws SSLProtocolException;     /*     * Sends a change cipher spec message and updates the write side     * cipher state so that future messages use the just-negotiated spec.     */    void sendChangeCipherSpec(Finished mesg, boolean lastMessage)            throws IOException {         output.flush(); // i.e. handshake data         /*         * The write cipher state is protected by the connection write lock         * so we must grab it while making the change. We also         * make sure no writes occur between sending the ChangeCipherSpec         * message, installing the new cipher state, and sending the         * Finished message.         *         * We already hold SSLEngine/SSLSocket "this" by virtue         * of this being called from the readRecord code.         */        OutputRecord r;        if (conn != null) {            r = new OutputRecord(Record.ct_change_cipher_spec);        } else {            r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);        }         r.setVersion(protocolVersion);        r.write(1);     // single byte of data         if (conn != null) {            conn.writeLock.lock();            try {                conn.writeRecord(r);                conn.changeWriteCiphers();                if (debug != null && Debug.isOn("handshake")) {                    mesg.print(System.out);                }                mesg.write(output);                output.flush();            } finally {                conn.writeLock.unlock();            }        } else {            synchronized (engine.writeLock) {                engine.writeRecord((EngineOutputRecord)r);                engine.changeWriteCiphers();                if (debug != null && Debug.isOn("handshake")) {                    mesg.print(System.out);                }                mesg.write(output);                 if (lastMessage) {                    output.setFinishedMsg();                }                output.flush();            }        }    }     /*     * Single access point to key calculation logic.  Given the     * pre-master secret and the nonces from client and server,     * produce all the keying material to be used.     */    void calculateKeys(SecretKey preMasterSecret, ProtocolVersion version) {        SecretKey master = calculateMasterSecret(preMasterSecret, version);        session.setMasterSecret(master);

Lines 501–1000 of 1386. Previous lines