diff options
author | Sergio Giro <sgiro@google.com> | 2016-02-01 14:37:23 +0000 |
---|---|---|
committer | Sergio Giro <sgiro@google.com> | 2016-02-01 15:16:12 +0000 |
commit | 397d32894b89b506dc318e0f83446187c9b76ebe (patch) | |
tree | 8229ff72c8cbb06f49dce3a8382930919fa6fc2b /bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java | |
parent | 9b30eb05e5be69d51881a0d1b31e503e97acd784 (diff) | |
parent | 6d876f3f0ae553704a1dcf7e89003fcf14717037 (diff) | |
download | android_external_bouncycastle-397d32894b89b506dc318e0f83446187c9b76ebe.tar.gz android_external_bouncycastle-397d32894b89b506dc318e0f83446187c9b76ebe.tar.bz2 android_external_bouncycastle-397d32894b89b506dc318e0f83446187c9b76ebe.zip |
Merge remote-tracking branch 'aosp/upstream-master' into merge-152-from-upstream
As to set a common ancestor for future merges from aosp/upstream-master
(when updating to new versions of bouncycastle).
We'll override all the changes of this commit with patch
https://android-review.googlesource.com/#/c/199872
Change-Id: I53a7f797b520a6e119878dbae53246cdcc585ddf
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java new file mode 100644 index 0000000..2d36788 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/DTLSServerProtocol.java @@ -0,0 +1,681 @@ +package org.bouncycastle.crypto.tls; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.util.Arrays; + +public class DTLSServerProtocol + extends DTLSProtocol +{ + protected boolean verifyRequests = true; + + public DTLSServerProtocol(SecureRandom secureRandom) + { + super(secureRandom); + } + + public boolean getVerifyRequests() + { + return verifyRequests; + } + + public void setVerifyRequests(boolean verifyRequests) + { + this.verifyRequests = verifyRequests; + } + + public DTLSTransport accept(TlsServer server, DatagramTransport transport) + throws IOException + { + if (server == null) + { + throw new IllegalArgumentException("'server' cannot be null"); + } + if (transport == null) + { + throw new IllegalArgumentException("'transport' cannot be null"); + } + + SecurityParameters securityParameters = new SecurityParameters(); + securityParameters.entity = ConnectionEnd.server; + + ServerHandshakeState state = new ServerHandshakeState(); + state.server = server; + state.serverContext = new TlsServerContextImpl(secureRandom, securityParameters); + + securityParameters.serverRandom = TlsProtocol.createRandomBlock(server.shouldUseGMTUnixTime(), + state.serverContext.getNonceRandomGenerator()); + + server.init(state.serverContext); + + DTLSRecordLayer recordLayer = new DTLSRecordLayer(transport, state.serverContext, server, ContentType.handshake); + + // TODO Need to handle sending of HelloVerifyRequest without entering a full connection + + try + { + return serverHandshake(state, recordLayer); + } + catch (TlsFatalAlert fatalAlert) + { + recordLayer.fail(fatalAlert.getAlertDescription()); + throw fatalAlert; + } + catch (IOException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw e; + } + catch (RuntimeException e) + { + recordLayer.fail(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer) + throws IOException + { + SecurityParameters securityParameters = state.serverContext.getSecurityParameters(); + DTLSReliableHandshake handshake = new DTLSReliableHandshake(state.serverContext, recordLayer); + + DTLSReliableHandshake.Message clientMessage = handshake.receiveMessage(); + + { + // NOTE: After receiving a record from the client, we discover the record layer version + ProtocolVersion client_version = recordLayer.getDiscoveredPeerVersion(); + // TODO Read RFCs for guidance on the expected record layer version number + state.serverContext.setClientVersion(client_version); + } + + if (clientMessage.getType() == HandshakeType.client_hello) + { + processClientHello(state, clientMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + { + byte[] serverHelloBody = generateServerHello(state); + + if (state.maxFragmentLength >= 0) + { + int plainTextLimit = 1 << (8 + state.maxFragmentLength); + recordLayer.setPlaintextLimit(plainTextLimit); + } + + securityParameters.cipherSuite = state.selectedCipherSuite; + securityParameters.compressionAlgorithm = state.selectedCompressionMethod; + securityParameters.prfAlgorithm = TlsProtocol.getPRFAlgorithm(state.serverContext, + state.selectedCipherSuite); + + /* + * 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. + */ + securityParameters.verifyDataLength = 12; + + handshake.sendMessage(HandshakeType.server_hello, serverHelloBody); + } + + handshake.notifyHelloComplete(); + + Vector serverSupplementalData = state.server.getServerSupplementalData(); + if (serverSupplementalData != null) + { + byte[] supplementalDataBody = generateSupplementalData(serverSupplementalData); + handshake.sendMessage(HandshakeType.supplemental_data, supplementalDataBody); + } + + state.keyExchange = state.server.getKeyExchange(); + state.keyExchange.init(state.serverContext); + + state.serverCredentials = state.server.getCredentials(); + + Certificate serverCertificate = null; + + if (state.serverCredentials == null) + { + state.keyExchange.skipServerCredentials(); + } + else + { + state.keyExchange.processServerCredentials(state.serverCredentials); + + serverCertificate = state.serverCredentials.getCertificate(); + byte[] certificateBody = generateCertificate(serverCertificate); + handshake.sendMessage(HandshakeType.certificate, certificateBody); + } + + // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus + if (serverCertificate == null || serverCertificate.isEmpty()) + { + state.allowCertificateStatus = false; + } + + if (state.allowCertificateStatus) + { + CertificateStatus certificateStatus = state.server.getCertificateStatus(); + if (certificateStatus != null) + { + byte[] certificateStatusBody = generateCertificateStatus(state, certificateStatus); + handshake.sendMessage(HandshakeType.certificate_status, certificateStatusBody); + } + } + + byte[] serverKeyExchange = state.keyExchange.generateServerKeyExchange(); + if (serverKeyExchange != null) + { + handshake.sendMessage(HandshakeType.server_key_exchange, serverKeyExchange); + } + + if (state.serverCredentials != null) + { + state.certificateRequest = state.server.getCertificateRequest(); + if (state.certificateRequest != null) + { + state.keyExchange.validateCertificateRequest(state.certificateRequest); + + byte[] certificateRequestBody = generateCertificateRequest(state, state.certificateRequest); + handshake.sendMessage(HandshakeType.certificate_request, certificateRequestBody); + + TlsUtils.trackHashAlgorithms(handshake.getHandshakeHash(), + state.certificateRequest.getSupportedSignatureAlgorithms()); + } + } + + handshake.sendMessage(HandshakeType.server_hello_done, TlsUtils.EMPTY_BYTES); + + handshake.getHandshakeHash().sealHashAlgorithms(); + + clientMessage = handshake.receiveMessage(); + + if (clientMessage.getType() == HandshakeType.supplemental_data) + { + processClientSupplementalData(state, clientMessage.getBody()); + clientMessage = handshake.receiveMessage(); + } + else + { + state.server.processClientSupplementalData(null); + } + + if (state.certificateRequest == null) + { + state.keyExchange.skipClientCredentials(); + } + else + { + if (clientMessage.getType() == HandshakeType.certificate) + { + processClientCertificate(state, clientMessage.getBody()); + clientMessage = handshake.receiveMessage(); + } + else + { + if (TlsUtils.isTLSv12(state.serverContext)) + { + /* + * 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. + */ + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + notifyClientCertificate(state, Certificate.EMPTY_CHAIN); + } + } + + if (clientMessage.getType() == HandshakeType.client_key_exchange) + { + processClientKeyExchange(state, clientMessage.getBody()); + } + else + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + TlsHandshakeHash prepareFinishHash = handshake.prepareToFinish(); + securityParameters.sessionHash = TlsProtocol.getCurrentPRFHash(state.serverContext, prepareFinishHash, null); + + TlsProtocol.establishMasterSecret(state.serverContext, state.keyExchange); + recordLayer.initPendingEpoch(state.server.getCipher()); + + /* + * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing + * capability (i.e., all certificates except those containing fixed Diffie-Hellman + * parameters). + */ + if (expectCertificateVerifyMessage(state)) + { + byte[] certificateVerifyBody = handshake.receiveMessageBody(HandshakeType.certificate_verify); + processCertificateVerify(state, certificateVerifyBody, prepareFinishHash); + } + + // NOTE: Calculated exclusive of the actual Finished message from the client + byte[] expectedClientVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.client_finished, + TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null)); + processFinished(handshake.receiveMessageBody(HandshakeType.finished), expectedClientVerifyData); + + if (state.expectSessionTicket) + { + NewSessionTicket newSessionTicket = state.server.getNewSessionTicket(); + byte[] newSessionTicketBody = generateNewSessionTicket(state, newSessionTicket); + handshake.sendMessage(HandshakeType.session_ticket, newSessionTicketBody); + } + + // NOTE: Calculated exclusive of the Finished message itself + byte[] serverVerifyData = TlsUtils.calculateVerifyData(state.serverContext, ExporterLabel.server_finished, + TlsProtocol.getCurrentPRFHash(state.serverContext, handshake.getHandshakeHash(), null)); + handshake.sendMessage(HandshakeType.finished, serverVerifyData); + + handshake.finish(); + + state.server.notifyHandshakeComplete(); + + return new DTLSTransport(recordLayer); + } + + protected byte[] generateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificateRequest.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateCertificateStatus(ServerHandshakeState state, CertificateStatus certificateStatus) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + certificateStatus.encode(buf); + return buf.toByteArray(); + } + + protected byte[] generateNewSessionTicket(ServerHandshakeState state, NewSessionTicket newSessionTicket) + throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + newSessionTicket.encode(buf); + return buf.toByteArray(); + } + + 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 + || CipherSuite.isSCSV(state.selectedCipherSuite) + || !TlsUtils.isValidCipherSuiteForVersion(state.selectedCipherSuite, server_version)) + { + 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 (securityParameters.extendedMasterSecret) + { + state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions); + TlsExtensionsUtils.addExtendedMasterSecretExtension(state.serverExtensions); + } + + if (state.serverExtensions != null) + { + securityParameters.encryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(state.serverExtensions); + + 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(); + } + + protected void notifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate) + throws IOException + { + if (state.certificateRequest == null) + { + throw new IllegalStateException(); + } + + if (state.clientCertificate != null) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + state.clientCertificate = clientCertificate; + + if (clientCertificate.isEmpty()) + { + state.keyExchange.skipClientCredentials(); + } + else + { + + /* + * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request + * message was non-empty, one of the certificates in the certificate chain SHOULD be + * issued by one of the listed CAs. + */ + + state.clientCertificateType = TlsUtils.getClientCertificateType(clientCertificate, + state.serverCredentials.getCertificate()); + + state.keyExchange.processClientCertificate(clientCertificate); + } + + /* + * RFC 5246 7.4.6. If the client does not send any certificates, the server MAY at its + * discretion either continue the handshake without client authentication, or respond with a + * fatal handshake_failure alert. Also, if some aspect of the certificate chain was + * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its + * discretion either continue the handshake (considering the client unauthenticated) or send + * a fatal alert. + */ + state.server.notifyClientCertificate(clientCertificate); + } + + protected void processClientCertificate(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + Certificate clientCertificate = Certificate.parse(buf); + + TlsProtocol.assertEmpty(buf); + + notifyClientCertificate(state, clientCertificate); + } + + protected void processCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + TlsServerContextImpl context = state.serverContext; + DigitallySigned clientCertificateVerify = DigitallySigned.parse(context, buf); + + TlsProtocol.assertEmpty(buf); + + // Verify the CertificateVerify message contains a correct signature. + boolean verified = false; + try + { + byte[] hash; + if (TlsUtils.isTLSv12(context)) + { + hash = prepareFinishHash.getFinalHash(clientCertificateVerify.getAlgorithm().getHash()); + } + else + { + hash = context.getSecurityParameters().getSessionHash(); + } + + org.bouncycastle.asn1.x509.Certificate x509Cert = state.clientCertificate.getCertificateAt(0); + SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo(); + AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyInfo); + + TlsSigner tlsSigner = TlsUtils.createTlsSigner(state.clientCertificateType); + tlsSigner.init(context); + verified = tlsSigner.verifyRawSignature(clientCertificateVerify.getAlgorithm(), + clientCertificateVerify.getSignature(), publicKey, hash); + } + catch (Exception e) + { + } + + if (!verified) + { + throw new TlsFatalAlert(AlertDescription.decrypt_error); + } + } + + protected void processClientHello(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + // TODO Read RFCs for guidance on the expected record layer version number + ProtocolVersion client_version = TlsUtils.readVersion(buf); + if (!client_version.isDTLS()) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + /* + * Read the client random + */ + byte[] client_random = TlsUtils.readFully(32, buf); + + byte[] sessionID = TlsUtils.readOpaque8(buf); + if (sessionID.length > 32) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347 + byte[] cookie = TlsUtils.readOpaque8(buf); + + int cipher_suites_length = TlsUtils.readUint16(buf); + if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + /* + * NOTE: "If the session_id field is not empty (implying a session resumption request) this + * vector must include at least the cipher_suite from that session." + */ + state.offeredCipherSuites = TlsUtils.readUint16Array(cipher_suites_length / 2, buf); + + int compression_methods_length = TlsUtils.readUint8(buf); + if (compression_methods_length < 1) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + + state.offeredCompressionMethods = TlsUtils.readUint8Array(compression_methods_length, buf); + + /* + * TODO 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. + */ + state.clientExtensions = TlsProtocol.readExtensions(buf); + + TlsServerContextImpl context = state.serverContext; + SecurityParameters securityParameters = context.getSecurityParameters(); + + securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(state.clientExtensions); + + context.setClientVersion(client_version); + + state.server.notifyClientVersion(client_version); + state.server.notifyFallback(Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)); + + securityParameters.clientRandom = client_random; + + state.server.notifyOfferedCipherSuites(state.offeredCipherSuites); + state.server.notifyOfferedCompressionMethods(state.offeredCompressionMethods); + + /* + * RFC 5746 3.6. Server Behavior: Initial Handshake + */ + { + /* + * 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. + */ + + /* + * When a ClientHello is received, the server MUST check if it includes the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag + * to TRUE. + */ + if (Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) + { + state.secure_renegotiation = true; + } + + /* + * The server MUST check if the "renegotiation_info" extension is included in the + * ClientHello. + */ + byte[] renegExtData = TlsUtils.getExtensionData(state.clientExtensions, TlsProtocol.EXT_RenegotiationInfo); + if (renegExtData != null) + { + /* + * If the extension is present, set secure_renegotiation flag to TRUE. The + * server MUST then verify that the length of the "renegotiated_connection" + * field is zero, and if it is not, MUST abort the handshake. + */ + state.secure_renegotiation = true; + + if (!Arrays.constantTimeAreEqual(renegExtData, TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES))) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + } + } + + state.server.notifySecureRenegotiation(state.secure_renegotiation); + + if (state.clientExtensions != null) + { + state.server.processClientExtensions(state.clientExtensions); + } + } + + protected void processClientKeyExchange(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + + state.keyExchange.processClientKeyExchange(buf); + + TlsProtocol.assertEmpty(buf); + } + + protected void processClientSupplementalData(ServerHandshakeState state, byte[] body) + throws IOException + { + ByteArrayInputStream buf = new ByteArrayInputStream(body); + Vector clientSupplementalData = TlsProtocol.readSupplementalDataMessage(buf); + state.server.processClientSupplementalData(clientSupplementalData); + } + + protected boolean expectCertificateVerifyMessage(ServerHandshakeState state) + { + return state.clientCertificateType >= 0 && TlsUtils.hasSigningCapability(state.clientCertificateType); + } + + protected static class ServerHandshakeState + { + TlsServer server = null; + TlsServerContextImpl serverContext = null; + int[] offeredCipherSuites; + short[] offeredCompressionMethods; + Hashtable clientExtensions; + int selectedCipherSuite = -1; + short selectedCompressionMethod = -1; + boolean secure_renegotiation = false; + short maxFragmentLength = -1; + boolean allowCertificateStatus = false; + boolean expectSessionTicket = false; + Hashtable serverExtensions = null; + TlsKeyExchange keyExchange = null; + TlsCredentials serverCredentials = null; + CertificateRequest certificateRequest = null; + short clientCertificateType = -1; + Certificate clientCertificate = null; + } +} |