/**
   * Get the active cipher suites.
   *
   * <p>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.
   *
   * <p>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.
   *
   * <p>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;
  }
  /**
   * Prior to handshaking, activate the handshake and initialize the version, input stream and
   * output stream.
   */
  void activate(ProtocolVersion helloVersion) throws IOException {
    if (activeProtocols == null) {
      activeProtocols = getActiveProtocols();
    }

    if (activeProtocols.collection().isEmpty() || activeProtocols.max.v == ProtocolVersion.NONE.v) {
      throw new SSLHandshakeException("No appropriate protocol");
    }

    if (activeCipherSuites == null) {
      activeCipherSuites = getActiveCipherSuites();
    }

    if (activeCipherSuites.collection().isEmpty()) {
      throw new SSLHandshakeException("No appropriate cipher suite");
    }

    // temporary protocol version until the actual protocol version
    // is negotiated in the Hello exchange. This affects the record
    // version we sent with the ClientHello.
    if (!isInitialHandshake) {
      protocolVersion = activeProtocolVersion;
    } else {
      protocolVersion = activeProtocols.max;
    }

    if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {
      helloVersion = activeProtocols.helloVersion;
    }

    // We accumulate digests of the handshake messages so that
    // we can read/write CertificateVerify and Finished messages,
    // getting assurance against some particular active attacks.
    Set<String> localSupportedHashAlgorithms =
        SignatureAndHashAlgorithm.getHashAlgorithmNames(getLocalSupportedSignAlgs());
    handshakeHash = new HandshakeHash(!isClient, needCertVerify, localSupportedHashAlgorithms);

    // Generate handshake input/output stream.
    input = new HandshakeInStream(handshakeHash);
    if (conn != null) {
      output = new HandshakeOutStream(protocolVersion, helloVersion, handshakeHash, conn);
      conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
      conn.getAppInputStream().r.setHelloVersion(helloVersion);
      conn.getAppOutputStream().r.setHelloVersion(helloVersion);
    } else {
      output = new HandshakeOutStream(protocolVersion, helloVersion, handshakeHash, engine);
      engine.inputRecord.setHandshakeHash(handshakeHash);
      engine.inputRecord.setHelloVersion(helloVersion);
      engine.outputRecord.setHelloVersion(helloVersion);
    }

    // move state to activated
    state = -1;
  }