Exemplo n.º 1
0
  public void generateClientKeyExchange(OutputStream os) throws IOException {
    /*
     * Choose a PremasterSecret and send it encrypted to the server
     */
    premasterSecret = new byte[48];
    context.getSecureRandom().nextBytes(premasterSecret);
    TlsUtils.writeVersion(premasterSecret, 0);

    PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine());
    encoding.init(
        true, new ParametersWithRandom(this.rsaServerPublicKey, context.getSecureRandom()));

    try {
      byte[] keData = encoding.processBlock(premasterSecret, 0, premasterSecret.length);
      TlsUtils.writeUint24(keData.length + 2, os);
      TlsUtils.writeOpaque16(keData, os);
    } catch (InvalidCipherTextException e) {
      /*
       * This should never happen, only during decryption.
       */
      throw new TlsFatalAlert(AlertDescription.internal_error);
    }
  }
Exemplo n.º 2
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();
  }
Exemplo n.º 3
0
  /**
   * Connects to the remote system using client authentication
   *
   * @param tlsClient
   * @throws IOException If handshake was not successful.
   */
  public void connect(TlsClient tlsClient) throws IOException {
    if (tlsClient == null) {
      throw new IllegalArgumentException("'tlsClient' cannot be null");
    }
    if (this.tlsClient != null) {
      throw new IllegalStateException("connect can only be called once");
    }

    /*
     * Send Client hello
     *
     * First, generate some random data.
     */
    this.securityParameters = new SecurityParameters();
    this.securityParameters.clientRandom = new byte[32];
    random.nextBytes(securityParameters.clientRandom);
    TlsUtils.writeGMTUnixTime(securityParameters.clientRandom, 0);

    this.tlsClientContext = new TlsClientContextImpl(random, securityParameters);

    this.rs.init(tlsClientContext);

    this.tlsClient = tlsClient;
    this.tlsClient.init(tlsClientContext);

    ByteArrayOutputStream os = new ByteArrayOutputStream();

    ProtocolVersion client_version = this.tlsClient.getClientVersion();
    this.tlsClientContext.setClientVersion(client_version);
    // TODO For SSLv3 support, server version needs to be set to ProtocolVersion.SSLv3
    this.tlsClientContext.setServerVersion(client_version);
    TlsUtils.writeVersion(client_version, os);

    os.write(securityParameters.clientRandom);

    /*
     * Length of Session id
     */
    TlsUtils.writeUint8((short) 0, os);

    /*
     * Cipher suites
     */
    this.offeredCipherSuites = this.tlsClient.getCipherSuites();

    // Integer -> byte[]
    this.clientExtensions = this.tlsClient.getClientExtensions();

    // Cipher Suites (and SCSV)
    {
      /*
       * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info"
       * extension, or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite
       * value in the ClientHello. Including both is NOT RECOMMENDED.
       */
      boolean noRenegExt =
          clientExtensions == null || clientExtensions.get(EXT_RenegotiationInfo) == null;

      int count = offeredCipherSuites.length;
      if (noRenegExt) {
        // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ++count;
      }

      TlsUtils.writeUint16(2 * count, os);
      TlsUtils.writeUint16Array(offeredCipherSuites, os);

      if (noRenegExt) {
        TlsUtils.writeUint16(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, os);
      }
    }

    // Compression methods
    this.offeredCompressionMethods = this.tlsClient.getCompressionMethods();

    TlsUtils.writeUint8((short) offeredCompressionMethods.length, os);
    TlsUtils.writeUint8Array(offeredCompressionMethods, os);

    // Extensions
    if (clientExtensions != null) {
      ByteArrayOutputStream ext = new ByteArrayOutputStream();

      Enumeration keys = clientExtensions.keys();
      while (keys.hasMoreElements()) {
        Integer extType = (Integer) keys.nextElement();
        writeExtension(ext, extType, (byte[]) clientExtensions.get(extType));
      }

      TlsUtils.writeOpaque16(ext.toByteArray(), os);
    }

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    TlsUtils.writeUint8(HandshakeType.client_hello, bos);
    TlsUtils.writeUint24(os.size(), bos);
    bos.write(os.toByteArray());
    byte[] message = bos.toByteArray();

    safeWriteMessage(ContentType.handshake, message, 0, message.length);

    connection_state = CS_CLIENT_HELLO_SEND;

    /*
     * We will now read data, until we have completed the handshake.
     */
    while (connection_state != CS_DONE) {
      safeReadData();
    }

    this.tlsInputStream = new TlsInputStream(this);
    this.tlsOutputStream = new TlsOutputStream(this);
  }