Ejemplo n.º 1
0
  protected byte[] generateServerHello(ServerHandshakeState state) throws IOException {
    SecurityParameters securityParameters = state.serverContext.getSecurityParameters();

    ByteArrayOutputStream buf = new ByteArrayOutputStream();

    ProtocolVersion server_version = state.server.getServerVersion();
    if (!server_version.isEqualOrEarlierVersionOf(state.serverContext.getClientVersion())) {
      throw new TlsFatalAlert(AlertDescription.internal_error);
    }

    // TODO Read RFCs for guidance on the expected record layer version number
    // recordStream.setReadVersion(server_version);
    // recordStream.setWriteVersion(server_version);
    // recordStream.setRestrictReadVersion(true);
    state.serverContext.setServerVersion(server_version);

    TlsUtils.writeVersion(state.serverContext.getServerVersion(), buf);

    buf.write(securityParameters.getServerRandom());

    /*
     * The server may return an empty session_id to indicate that the session will not be cached
     * and therefore cannot be resumed.
     */
    TlsUtils.writeOpaque8(TlsUtils.EMPTY_BYTES, buf);

    state.selectedCipherSuite = state.server.getSelectedCipherSuite();
    if (!Arrays.contains(state.offeredCipherSuites, state.selectedCipherSuite)
        || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
        || state.selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
      throw new TlsFatalAlert(AlertDescription.internal_error);
    }

    validateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.internal_error);

    state.selectedCompressionMethod = state.server.getSelectedCompressionMethod();
    if (!Arrays.contains(state.offeredCompressionMethods, state.selectedCompressionMethod)) {
      throw new TlsFatalAlert(AlertDescription.internal_error);
    }

    TlsUtils.writeUint16(state.selectedCipherSuite, buf);
    TlsUtils.writeUint8(state.selectedCompressionMethod, buf);

    state.serverExtensions = state.server.getServerExtensions();

    /*
     * RFC 5746 3.6. Server Behavior: Initial Handshake
     */
    if (state.secure_renegotiation) {
      byte[] renegExtData =
          TlsUtils.getExtensionData(state.serverExtensions, TlsProtocol.EXT_RenegotiationInfo);
      boolean noRenegExt = (null == renegExtData);

      if (noRenegExt) {
        /*
         * Note that sending a "renegotiation_info" extension in response to a ClientHello
         * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
         * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed
         * because the client is signaling its willingness to receive the extension via the
         * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
         */

        /*
         * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
         * "renegotiation_info" extension in the ServerHello message.
         */
        state.serverExtensions =
            TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions);
        state.serverExtensions.put(
            TlsProtocol.EXT_RenegotiationInfo,
            TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES));
      }
    }

    if (state.serverExtensions != null) {
      state.maxFragmentLength =
          evaluateMaxFragmentLengthExtension(
              state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);

      securityParameters.truncatedHMac =
          TlsExtensionsUtils.hasTruncatedHMacExtension(state.serverExtensions);

      state.allowCertificateStatus =
          TlsUtils.hasExpectedEmptyExtensionData(
              state.serverExtensions,
              TlsExtensionsUtils.EXT_status_request,
              AlertDescription.internal_error);

      state.expectSessionTicket =
          TlsUtils.hasExpectedEmptyExtensionData(
              state.serverExtensions,
              TlsProtocol.EXT_SessionTicket,
              AlertDescription.internal_error);

      TlsProtocol.writeExtensions(buf, state.serverExtensions);
    }

    return buf.toByteArray();
  }