diff options
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/TlsClientProtocol.java')
-rw-r--r-- | libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/TlsClientProtocol.java | 884 |
1 files changed, 0 insertions, 884 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/TlsClientProtocol.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/TlsClientProtocol.java deleted file mode 100644 index c6b56a9e8..000000000 --- a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/TlsClientProtocol.java +++ /dev/null @@ -1,884 +0,0 @@ -package org.spongycastle.crypto.tls; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -import org.spongycastle.crypto.prng.ThreadedSeedGenerator; -import org.spongycastle.util.Arrays; - -public class TlsClientProtocol - extends TlsProtocol -{ - protected TlsClient tlsClient = null; - protected TlsClientContextImpl tlsClientContext = null; - - protected byte[] selectedSessionID = null; - - protected TlsKeyExchange keyExchange = null; - protected TlsAuthentication authentication = null; - - protected CertificateStatus certificateStatus = null; - protected CertificateRequest certificateRequest = null; - - private static SecureRandom createSecureRandom() - { - /* - * We use our threaded seed generator to generate a good random seed. If the user has a - * better random seed, he should use the constructor with a SecureRandom. - */ - ThreadedSeedGenerator tsg = new ThreadedSeedGenerator(); - SecureRandom random = new SecureRandom(); - - /* - * Hopefully, 20 bytes in fast mode are good enough. - */ - random.setSeed(tsg.generateSeed(20, true)); - - return random; - } - - public TlsClientProtocol(InputStream input, OutputStream output) - { - this(input, output, createSecureRandom()); - } - - public TlsClientProtocol(InputStream input, OutputStream output, SecureRandom secureRandom) - { - super(input, output, secureRandom); - } - - /** - * Initiates a TLS handshake in the role of client - * - * @param tlsClient The {@link TlsClient} to use for the handshake. - * @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"); - } - - this.tlsClient = tlsClient; - - this.securityParameters = new SecurityParameters(); - this.securityParameters.entity = ConnectionEnd.client; - this.securityParameters.clientRandom = createRandomBlock(secureRandom); - - this.tlsClientContext = new TlsClientContextImpl(secureRandom, securityParameters); - this.tlsClient.init(tlsClientContext); - this.recordStream.init(tlsClientContext); - - TlsSession sessionToResume = tlsClient.getSessionToResume(); - if (sessionToResume != null) - { - SessionParameters sessionParameters = sessionToResume.exportSessionParameters(); - if (sessionParameters != null) - { - this.tlsSession = sessionToResume; - this.sessionParameters = sessionParameters; - } - } - - sendClientHelloMessage(); - this.connection_state = CS_CLIENT_HELLO; - - completeHandshake(); - } - - protected void cleanupHandshake() - { - super.cleanupHandshake(); - - this.selectedSessionID = null; - this.keyExchange = null; - this.authentication = null; - this.certificateStatus = null; - this.certificateRequest = null; - } - - protected AbstractTlsContext getContext() - { - return tlsClientContext; - } - - protected TlsPeer getPeer() - { - return tlsClient; - } - - protected void handleHandshakeMessage(short type, byte[] data) - throws IOException - { - ByteArrayInputStream buf = new ByteArrayInputStream(data); - - if (this.resumedSession) - { - if (type != HandshakeType.finished || this.connection_state != CS_SERVER_HELLO) - { - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - processFinishedMessage(buf); - this.connection_state = CS_SERVER_FINISHED; - - sendFinishedMessage(); - this.connection_state = CS_CLIENT_FINISHED; - this.connection_state = CS_END; - - return; - } - - switch (type) - { - case HandshakeType.certificate: - { - switch (this.connection_state) - { - case CS_SERVER_HELLO: - { - handleSupplementalData(null); - // NB: Fall through to next case label - } - case CS_SERVER_SUPPLEMENTAL_DATA: - { - // Parse the Certificate message and send to cipher suite - - this.peerCertificate = Certificate.parse(buf); - - assertEmpty(buf); - - // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus - if (this.peerCertificate == null || this.peerCertificate.isEmpty()) - { - this.allowCertificateStatus = false; - } - - this.keyExchange.processServerCertificate(this.peerCertificate); - - this.authentication = tlsClient.getAuthentication(); - this.authentication.notifyServerCertificate(this.peerCertificate); - - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - this.connection_state = CS_SERVER_CERTIFICATE; - break; - } - case HandshakeType.certificate_status: - { - switch (this.connection_state) - { - case CS_SERVER_CERTIFICATE: - { - if (!this.allowCertificateStatus) - { - /* - * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the - * server MUST have included an extension of type "status_request" with empty - * "extension_data" in the extended server hello.. - */ - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - this.certificateStatus = CertificateStatus.parse(buf); - - assertEmpty(buf); - - // TODO[RFC 3546] Figure out how to provide this to the client/authentication. - - this.connection_state = CS_CERTIFICATE_STATUS; - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - break; - } - case HandshakeType.finished: - { - switch (this.connection_state) - { - case CS_CLIENT_FINISHED: - { - processFinishedMessage(buf); - this.connection_state = CS_SERVER_FINISHED; - this.connection_state = CS_END; - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - break; - } - case HandshakeType.server_hello: - { - switch (this.connection_state) - { - case CS_CLIENT_HELLO: - { - receiveServerHelloMessage(buf); - this.connection_state = CS_SERVER_HELLO; - - if (this.securityParameters.maxFragmentLength >= 0) - { - int plainTextLimit = 1 << (8 + this.securityParameters.maxFragmentLength); - recordStream.setPlaintextLimit(plainTextLimit); - } - - this.securityParameters.prfAlgorithm = getPRFAlgorithm(getContext(), - this.securityParameters.getCipherSuite()); - - /* - * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify - * verify_data_length has a verify_data_length equal to 12. This includes all - * existing cipher suites. - */ - this.securityParameters.verifyDataLength = 12; - - this.recordStream.notifyHelloComplete(); - - if (this.resumedSession) - { - this.securityParameters.masterSecret = Arrays.clone(this.sessionParameters.getMasterSecret()); - this.recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher()); - - sendChangeCipherSpecMessage(); - } - else - { - invalidateSession(); - - if (this.selectedSessionID.length > 0) - { - this.tlsSession = new TlsSessionImpl(this.selectedSessionID, null); - } - } - - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - break; - } - case HandshakeType.supplemental_data: - { - switch (this.connection_state) - { - case CS_SERVER_HELLO: - { - handleSupplementalData(readSupplementalDataMessage(buf)); - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - break; - } - case HandshakeType.server_hello_done: - { - switch (this.connection_state) - { - case CS_SERVER_HELLO: - { - handleSupplementalData(null); - // NB: Fall through to next case label - } - case CS_SERVER_SUPPLEMENTAL_DATA: - { - // There was no server certificate message; check it's OK - this.keyExchange.skipServerCredentials(); - this.authentication = null; - - // NB: Fall through to next case label - } - case CS_SERVER_CERTIFICATE: - case CS_CERTIFICATE_STATUS: - { - // There was no server key exchange message; check it's OK - this.keyExchange.skipServerKeyExchange(); - - // NB: Fall through to next case label - } - case CS_SERVER_KEY_EXCHANGE: - case CS_CERTIFICATE_REQUEST: - { - assertEmpty(buf); - - this.connection_state = CS_SERVER_HELLO_DONE; - - this.recordStream.getHandshakeHash().sealHashAlgorithms(); - - Vector clientSupplementalData = tlsClient.getClientSupplementalData(); - if (clientSupplementalData != null) - { - sendSupplementalDataMessage(clientSupplementalData); - } - this.connection_state = CS_CLIENT_SUPPLEMENTAL_DATA; - - TlsCredentials clientCreds = null; - if (certificateRequest == null) - { - this.keyExchange.skipClientCredentials(); - } - else - { - clientCreds = this.authentication.getClientCredentials(certificateRequest); - - if (clientCreds == null) - { - this.keyExchange.skipClientCredentials(); - - /* - * RFC 5246 If no suitable certificate is available, the client MUST send a - * certificate message containing no certificates. - * - * NOTE: In previous RFCs, this was SHOULD instead of MUST. - */ - sendCertificateMessage(Certificate.EMPTY_CHAIN); - } - else - { - this.keyExchange.processClientCredentials(clientCreds); - - sendCertificateMessage(clientCreds.getCertificate()); - } - } - - this.connection_state = CS_CLIENT_CERTIFICATE; - - /* - * Send the client key exchange message, depending on the key exchange we are using - * in our CipherSuite. - */ - sendClientKeyExchangeMessage(); - this.connection_state = CS_CLIENT_KEY_EXCHANGE; - - establishMasterSecret(getContext(), keyExchange); - recordStream.setPendingConnectionState(getPeer().getCompression(), getPeer().getCipher()); - - TlsHandshakeHash prepareFinishHash = recordStream.prepareToFinish(); - - if (clientCreds != null && clientCreds instanceof TlsSignerCredentials) - { - TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds; - - /* - * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 - */ - SignatureAndHashAlgorithm signatureAndHashAlgorithm; - byte[] hash; - - if (TlsUtils.isTLSv12(getContext())) - { - signatureAndHashAlgorithm = signerCredentials.getSignatureAndHashAlgorithm(); - if (signatureAndHashAlgorithm == null) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - hash = prepareFinishHash.getFinalHash(signatureAndHashAlgorithm.getHash()); - } - else - { - signatureAndHashAlgorithm = null; - hash = getCurrentPRFHash(getContext(), prepareFinishHash, null); - } - - byte[] signature = signerCredentials.generateCertificateSignature(hash); - DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); - sendCertificateVerifyMessage(certificateVerify); - - this.connection_state = CS_CERTIFICATE_VERIFY; - } - - sendChangeCipherSpecMessage(); - sendFinishedMessage(); - this.connection_state = CS_CLIENT_FINISHED; - break; - } - default: - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - break; - } - case HandshakeType.server_key_exchange: - { - switch (this.connection_state) - { - case CS_SERVER_HELLO: - { - handleSupplementalData(null); - // NB: Fall through to next case label - } - case CS_SERVER_SUPPLEMENTAL_DATA: - { - // There was no server certificate message; check it's OK - this.keyExchange.skipServerCredentials(); - this.authentication = null; - - // NB: Fall through to next case label - } - case CS_SERVER_CERTIFICATE: - case CS_CERTIFICATE_STATUS: - { - this.keyExchange.processServerKeyExchange(buf); - - assertEmpty(buf); - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - this.connection_state = CS_SERVER_KEY_EXCHANGE; - break; - } - case HandshakeType.certificate_request: - { - switch (this.connection_state) - { - case CS_SERVER_CERTIFICATE: - case CS_CERTIFICATE_STATUS: - { - // There was no server key exchange message; check it's OK - this.keyExchange.skipServerKeyExchange(); - - // NB: Fall through to next case label - } - case CS_SERVER_KEY_EXCHANGE: - { - if (this.authentication == null) - { - /* - * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server - * to request client identification. - */ - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - - this.certificateRequest = CertificateRequest.parse(getContext(), buf); - - assertEmpty(buf); - - this.keyExchange.validateCertificateRequest(this.certificateRequest); - - /* - * TODO Give the client a chance to immediately select the CertificateVerify hash - * algorithm here to avoid tracking the other hash algorithms unnecessarily? - */ - TlsUtils.trackHashAlgorithms(this.recordStream.getHandshakeHash(), - this.certificateRequest.getSupportedSignatureAlgorithms()); - - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - this.connection_state = CS_CERTIFICATE_REQUEST; - break; - } - case HandshakeType.session_ticket: - { - switch (this.connection_state) - { - case CS_CLIENT_FINISHED: - { - if (!this.expectSessionTicket) - { - /* - * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a - * SessionTicket extension in the ServerHello. - */ - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - - /* - * RFC 5077 3.4. If the client receives a session ticket from the server, then it - * discards any Session ID that was sent in the ServerHello. - */ - invalidateSession(); - - receiveNewSessionTicketMessage(buf); - this.connection_state = CS_SERVER_SESSION_TICKET; - break; - } - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - } - case HandshakeType.hello_request: - { - assertEmpty(buf); - - /* - * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the - * client is currently negotiating a session. This message may be ignored by the client - * if it does not wish to renegotiate a session, or the client may, if it wishes, - * respond with a no_renegotiation alert. - */ - if (this.connection_state == CS_END) - { - /* - * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal - * handshake_failure alert. - */ - if (TlsUtils.isSSL(getContext())) - { - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - - String message = "Renegotiation not supported"; - raiseWarning(AlertDescription.no_renegotiation, message); - } - break; - } - case HandshakeType.client_hello: - case HandshakeType.client_key_exchange: - case HandshakeType.certificate_verify: - case HandshakeType.hello_verify_request: - default: - throw new TlsFatalAlert(AlertDescription.unexpected_message); - } - } - - protected void handleSupplementalData(Vector serverSupplementalData) - throws IOException - { - this.tlsClient.processServerSupplementalData(serverSupplementalData); - this.connection_state = CS_SERVER_SUPPLEMENTAL_DATA; - - this.keyExchange = tlsClient.getKeyExchange(); - this.keyExchange.init(getContext()); - } - - protected void receiveNewSessionTicketMessage(ByteArrayInputStream buf) - throws IOException - { - NewSessionTicket newSessionTicket = NewSessionTicket.parse(buf); - - TlsProtocol.assertEmpty(buf); - - tlsClient.notifyNewSessionTicket(newSessionTicket); - } - - protected void receiveServerHelloMessage(ByteArrayInputStream buf) - throws IOException - { - ProtocolVersion server_version = TlsUtils.readVersion(buf); - if (server_version.isDTLS()) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - // Check that this matches what the server is sending in the record layer - if (!server_version.equals(this.recordStream.getReadVersion())) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - ProtocolVersion client_version = getContext().getClientVersion(); - if (!server_version.isEqualOrEarlierVersionOf(client_version)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - this.recordStream.setWriteVersion(server_version); - getContext().setServerVersion(server_version); - this.tlsClient.notifyServerVersion(server_version); - - /* - * Read the server random - */ - this.securityParameters.serverRandom = TlsUtils.readFully(32, buf); - - this.selectedSessionID = TlsUtils.readOpaque8(buf); - if (this.selectedSessionID.length > 32) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - this.tlsClient.notifySessionID(this.selectedSessionID); - - this.resumedSession = this.selectedSessionID.length > 0 && this.tlsSession != null - && Arrays.areEqual(this.selectedSessionID, this.tlsSession.getSessionID()); - - /* - * Find out which CipherSuite the server has chosen and check that it was one of the offered - * ones. - */ - int selectedCipherSuite = TlsUtils.readUint16(buf); - if (!Arrays.contains(this.offeredCipherSuites, selectedCipherSuite) - || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL - || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - this.tlsClient.notifySelectedCipherSuite(selectedCipherSuite); - - /* - * Find out which CompressionMethod the server has chosen and check that it was one of the - * offered ones. - */ - short selectedCompressionMethod = TlsUtils.readUint8(buf); - if (!Arrays.contains(this.offeredCompressionMethods, selectedCompressionMethod)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - this.tlsClient.notifySelectedCompressionMethod(selectedCompressionMethod); - - /* - * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server - * hello message when the client has requested extended functionality via the extended - * client hello message specified in Section 2.1. ... Note that the extended server hello - * message is only sent in response to an extended client hello message. This prevents the - * possibility that the extended server hello message could "break" existing TLS 1.0 - * clients. - */ - this.serverExtensions = readExtensions(buf); - - /* - * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an - * extended client hello message. - * - * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server - * Hello is always allowed. - */ - if (this.serverExtensions != null) - { - Enumeration e = this.serverExtensions.keys(); - while (e.hasMoreElements()) - { - Integer extType = (Integer)e.nextElement(); - - /* - * RFC 5746 3.6. 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 (extType.equals(EXT_RenegotiationInfo)) - { - continue; - } - - /* - * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore - * extensions appearing in the client hello, and send a server hello containing no - * extensions[.] - */ - if (this.resumedSession) - { - // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats - // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats - // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats -// throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - /* - * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the - * same extension type appeared in the corresponding ClientHello. If a client - * receives an extension type in ServerHello that it did not request in the - * associated ClientHello, it MUST abort the handshake with an unsupported_extension - * fatal alert. - */ - if (null == TlsUtils.getExtensionData(this.clientExtensions, extType)) - { - throw new TlsFatalAlert(AlertDescription.unsupported_extension); - } - } - } - - /* - * RFC 5746 3.4. Client Behavior: Initial Handshake - */ - { - /* - * When a ServerHello is received, the client MUST check if it includes the - * "renegotiation_info" extension: - */ - byte[] renegExtData = TlsUtils.getExtensionData(this.serverExtensions, EXT_RenegotiationInfo); - if (renegExtData != null) - { - /* - * If the extension is present, set the secure_renegotiation flag to TRUE. The - * client MUST then verify that the length of the "renegotiated_connection" - * field is zero, and if it is not, MUST abort the handshake (by sending a fatal - * handshake_failure alert). - */ - this.secure_renegotiation = true; - - if (!Arrays.constantTimeAreEqual(renegExtData, createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) - { - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } - } - } - - // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming - this.tlsClient.notifySecureRenegotiation(this.secure_renegotiation); - - Hashtable sessionClientExtensions = clientExtensions, sessionServerExtensions = serverExtensions; - if (this.resumedSession) - { - if (selectedCipherSuite != this.sessionParameters.getCipherSuite() - || selectedCompressionMethod != this.sessionParameters.getCompressionAlgorithm()) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - - sessionClientExtensions = null; - sessionServerExtensions = this.sessionParameters.readServerExtensions(); - } - - this.securityParameters.cipherSuite = selectedCipherSuite; - this.securityParameters.compressionAlgorithm = selectedCompressionMethod; - - if (sessionServerExtensions != null) - { - this.securityParameters.maxFragmentLength = processMaxFragmentLengthExtension(sessionClientExtensions, - sessionServerExtensions, AlertDescription.illegal_parameter); - - this.securityParameters.truncatedHMac = TlsExtensionsUtils.hasTruncatedHMacExtension(sessionServerExtensions); - - /* - * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in - * a session resumption handshake. - */ - this.allowCertificateStatus = !this.resumedSession - && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, - TlsExtensionsUtils.EXT_status_request, AlertDescription.illegal_parameter); - - this.expectSessionTicket = !this.resumedSession - && TlsUtils.hasExpectedEmptyExtensionData(sessionServerExtensions, TlsProtocol.EXT_SessionTicket, - AlertDescription.illegal_parameter); - } - - if (sessionClientExtensions != null) - { - this.tlsClient.processServerExtensions(sessionServerExtensions); - } - } - - protected void sendCertificateVerifyMessage(DigitallySigned certificateVerify) - throws IOException - { - HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify); - - certificateVerify.encode(message); - - message.writeToRecordStream(); - } - - protected void sendClientHelloMessage() - throws IOException - { - this.recordStream.setWriteVersion(this.tlsClient.getClientHelloRecordLayerVersion()); - - ProtocolVersion client_version = this.tlsClient.getClientVersion(); - if (client_version.isDTLS()) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - getContext().setClientVersion(client_version); - - /* - * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a - * Session ID in the TLS ClientHello. - */ - byte[] session_id = TlsUtils.EMPTY_BYTES; - if (this.tlsSession != null) - { - session_id = this.tlsSession.getSessionID(); - if (session_id == null || session_id.length > 32) - { - session_id = TlsUtils.EMPTY_BYTES; - } - } - - this.offeredCipherSuites = this.tlsClient.getCipherSuites(); - - this.offeredCompressionMethods = this.tlsClient.getCompressionMethods(); - - if (session_id.length > 0 && this.sessionParameters != null) - { - if (!Arrays.contains(this.offeredCipherSuites, sessionParameters.getCipherSuite()) - || !Arrays.contains(this.offeredCompressionMethods, sessionParameters.getCompressionAlgorithm())) - { - session_id = TlsUtils.EMPTY_BYTES; - } - } - - this.clientExtensions = this.tlsClient.getClientExtensions(); - - HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); - - TlsUtils.writeVersion(client_version, message); - - message.write(this.securityParameters.getClientRandom()); - - TlsUtils.writeOpaque8(session_id, message); - - // 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. - */ - byte[] renegExtData = TlsUtils.getExtensionData(clientExtensions, EXT_RenegotiationInfo); - boolean noRenegExt = (null == renegExtData); - - boolean noSCSV = !Arrays.contains(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - - if (noRenegExt && noSCSV) - { - // TODO Consider whether to default to a client extension instead -// this.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.clientExtensions); -// this.clientExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); - this.offeredCipherSuites = Arrays.append(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - } - - TlsUtils.writeUint16ArrayWithUint16Length(offeredCipherSuites, message); - } - - TlsUtils.writeUint8ArrayWithUint8Length(offeredCompressionMethods, message); - - if (clientExtensions != null) - { - writeExtensions(message, clientExtensions); - } - - message.writeToRecordStream(); - } - - protected void sendClientKeyExchangeMessage() - throws IOException - { - HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange); - - this.keyExchange.generateClientKeyExchange(message); - - message.writeToRecordStream(); - } -} |