internal virtual DtlsTransport ClientHandshake(DtlsClientProtocol.ClientHandshakeState state, DtlsRecordLayer recordLayer) { SecurityParameters securityParameters = state.clientContext.SecurityParameters; DtlsReliableHandshake dtlsReliableHandshake = new DtlsReliableHandshake(state.clientContext, recordLayer); byte[] array = this.GenerateClientHello(state, state.client); dtlsReliableHandshake.SendMessage(1, array); DtlsReliableHandshake.Message message = dtlsReliableHandshake.ReceiveMessage(); while (message.Type == 3) { ProtocolVersion protocolVersion = recordLayer.ResetDiscoveredPeerVersion(); ProtocolVersion clientVersion = state.clientContext.ClientVersion; if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion)) { throw new TlsFatalAlert(47); } byte[] cookie = this.ProcessHelloVerifyRequest(state, message.Body); byte[] body = DtlsClientProtocol.PatchClientHelloWithCookie(array, cookie); dtlsReliableHandshake.ResetHandshakeMessagesDigest(); dtlsReliableHandshake.SendMessage(1, body); message = dtlsReliableHandshake.ReceiveMessage(); } if (message.Type != 2) { throw new TlsFatalAlert(10); } this.ReportServerVersion(state, recordLayer.DiscoveredPeerVersion); this.ProcessServerHello(state, message.Body); dtlsReliableHandshake.NotifyHelloComplete(); DtlsProtocol.ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength); if (state.resumedSession) { securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret); recordLayer.InitPendingEpoch(state.client.GetCipher()); byte[] expected_verify_data = TlsUtilities.CalculateVerifyData(state.clientContext, "server finished", TlsProtocol.GetCurrentPrfHash(state.clientContext, dtlsReliableHandshake.HandshakeHash, null)); this.ProcessFinished(dtlsReliableHandshake.ReceiveMessageBody(20), expected_verify_data); byte[] body2 = TlsUtilities.CalculateVerifyData(state.clientContext, "client finished", TlsProtocol.GetCurrentPrfHash(state.clientContext, dtlsReliableHandshake.HandshakeHash, null)); dtlsReliableHandshake.SendMessage(20, body2); dtlsReliableHandshake.Finish(); state.clientContext.SetResumableSession(state.tlsSession); state.client.NotifyHandshakeComplete(); return(new DtlsTransport(recordLayer)); } this.InvalidateSession(state); if (state.selectedSessionID.Length > 0) { state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null); } message = dtlsReliableHandshake.ReceiveMessage(); if (message.Type == 23) { this.ProcessServerSupplementalData(state, message.Body); message = dtlsReliableHandshake.ReceiveMessage(); } else { state.client.ProcessServerSupplementalData(null); } state.keyExchange = state.client.GetKeyExchange(); state.keyExchange.Init(state.clientContext); Certificate certificate = null; if (message.Type == 11) { certificate = this.ProcessServerCertificate(state, message.Body); message = dtlsReliableHandshake.ReceiveMessage(); } else { state.keyExchange.SkipServerCredentials(); } if (certificate == null || certificate.IsEmpty) { state.allowCertificateStatus = false; } if (message.Type == 22) { this.ProcessCertificateStatus(state, message.Body); message = dtlsReliableHandshake.ReceiveMessage(); } if (message.Type == 12) { this.ProcessServerKeyExchange(state, message.Body); message = dtlsReliableHandshake.ReceiveMessage(); } else { state.keyExchange.SkipServerKeyExchange(); } if (message.Type == 13) { this.ProcessCertificateRequest(state, message.Body); TlsUtilities.TrackHashAlgorithms(dtlsReliableHandshake.HandshakeHash, state.certificateRequest.SupportedSignatureAlgorithms); message = dtlsReliableHandshake.ReceiveMessage(); } if (message.Type != 14) { throw new TlsFatalAlert(10); } if (message.Body.Length != 0) { throw new TlsFatalAlert(50); } dtlsReliableHandshake.HandshakeHash.SealHashAlgorithms(); IList clientSupplementalData = state.client.GetClientSupplementalData(); if (clientSupplementalData != null) { byte[] body3 = DtlsProtocol.GenerateSupplementalData(clientSupplementalData); dtlsReliableHandshake.SendMessage(23, body3); } if (state.certificateRequest != null) { state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest); Certificate certificate2 = null; if (state.clientCredentials != null) { certificate2 = state.clientCredentials.Certificate; } if (certificate2 == null) { certificate2 = Certificate.EmptyChain; } byte[] body4 = DtlsProtocol.GenerateCertificate(certificate2); dtlsReliableHandshake.SendMessage(11, body4); } if (state.clientCredentials != null) { state.keyExchange.ProcessClientCredentials(state.clientCredentials); } else { state.keyExchange.SkipClientCredentials(); } byte[] body5 = this.GenerateClientKeyExchange(state); dtlsReliableHandshake.SendMessage(16, body5); TlsHandshakeHash tlsHandshakeHash = dtlsReliableHandshake.PrepareToFinish(); securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, tlsHandshakeHash, null); TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange); recordLayer.InitPendingEpoch(state.client.GetCipher()); if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials) { TlsSignerCredentials tlsSignerCredentials = (TlsSignerCredentials)state.clientCredentials; SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(state.clientContext, tlsSignerCredentials); byte[] hash; if (signatureAndHashAlgorithm == null) { hash = securityParameters.SessionHash; } else { hash = tlsHandshakeHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } byte[] signature = tlsSignerCredentials.GenerateCertificateSignature(hash); DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); byte[] body6 = this.GenerateCertificateVerify(state, certificateVerify); dtlsReliableHandshake.SendMessage(15, body6); } byte[] body7 = TlsUtilities.CalculateVerifyData(state.clientContext, "client finished", TlsProtocol.GetCurrentPrfHash(state.clientContext, dtlsReliableHandshake.HandshakeHash, null)); dtlsReliableHandshake.SendMessage(20, body7); if (state.expectSessionTicket) { message = dtlsReliableHandshake.ReceiveMessage(); if (message.Type != 4) { throw new TlsFatalAlert(10); } this.ProcessNewSessionTicket(state, message.Body); } byte[] expected_verify_data2 = TlsUtilities.CalculateVerifyData(state.clientContext, "server finished", TlsProtocol.GetCurrentPrfHash(state.clientContext, dtlsReliableHandshake.HandshakeHash, null)); this.ProcessFinished(dtlsReliableHandshake.ReceiveMessageBody(20), expected_verify_data2); dtlsReliableHandshake.Finish(); if (state.tlsSession != null) { state.sessionParameters = new SessionParameters.Builder().SetCipherSuite(securityParameters.CipherSuite).SetCompressionAlgorithm(securityParameters.CompressionAlgorithm).SetMasterSecret(securityParameters.MasterSecret).SetPeerCertificate(certificate).SetPskIdentity(securityParameters.PskIdentity).SetSrpIdentity(securityParameters.SrpIdentity).SetServerExtensions(state.serverExtensions).Build(); state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); state.clientContext.SetResumableSession(state.tlsSession); } state.client.NotifyHandshakeComplete(); return(new DtlsTransport(recordLayer)); }
internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer) { SecurityParameters securityParameters = state.clientContext.SecurityParameters; DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer); byte[] clientHelloBody = GenerateClientHello(state, state.client); handshake.SendMessage(HandshakeType.client_hello, clientHelloBody); DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage(); while (serverMessage.Type == HandshakeType.hello_verify_request) { ProtocolVersion recordLayerVersion = recordLayer.ResetDiscoveredPeerVersion(); ProtocolVersion client_version = state.clientContext.ClientVersion; /* * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and * 1.0) and not as part of version negotiation. */ if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body); byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie); handshake.ResetHandshakeMessagesDigest(); handshake.SendMessage(HandshakeType.client_hello, patched); serverMessage = handshake.ReceiveMessage(); } if (serverMessage.Type == HandshakeType.server_hello) { ReportServerVersion(state, recordLayer.DiscoveredPeerVersion); ProcessServerHello(state, serverMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } if (state.maxFragmentLength >= 0) { int plainTextLimit = 1 << (8 + state.maxFragmentLength); recordLayer.SetPlaintextLimit(plainTextLimit); } securityParameters.cipherSuite = state.selectedCipherSuite; securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod; securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext, 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.NotifyHelloComplete(); bool resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID); if (resumedSession) { if (securityParameters.CipherSuite != state.sessionParameters.CipherSuite || securityParameters.CompressionAlgorithm != state.sessionParameters.CompressionAlgorithm) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } IDictionary sessionServerExtensions = state.sessionParameters.ReadServerExtensions(); securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions); securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret); recordLayer.InitPendingEpoch(state.client.GetCipher()); // NOTE: Calculated exclusive of the actual Finished message from the server byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData); // NOTE: Calculated exclusive of the Finished message itself byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); handshake.SendMessage(HandshakeType.finished, resClientVerifyData); handshake.Finish(); state.clientContext.SetResumableSession(state.tlsSession); state.client.NotifyHandshakeComplete(); return(new DtlsTransport(recordLayer)); } InvalidateSession(state); if (state.selectedSessionID.Length > 0) { state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null); } serverMessage = handshake.ReceiveMessage(); if (serverMessage.Type == HandshakeType.supplemental_data) { ProcessServerSupplementalData(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { state.client.ProcessServerSupplementalData(null); } state.keyExchange = state.client.GetKeyExchange(); state.keyExchange.Init(state.clientContext); Certificate serverCertificate = null; if (serverMessage.Type == HandshakeType.certificate) { serverCertificate = ProcessServerCertificate(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, Certificate is optional state.keyExchange.SkipServerCredentials(); } // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus if (serverCertificate == null || serverCertificate.IsEmpty) { state.allowCertificateStatus = false; } if (serverMessage.Type == HandshakeType.certificate_status) { ProcessCertificateStatus(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, CertificateStatus is optional } if (serverMessage.Type == HandshakeType.server_key_exchange) { ProcessServerKeyExchange(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, ServerKeyExchange is optional state.keyExchange.SkipServerKeyExchange(); } if (serverMessage.Type == HandshakeType.certificate_request) { ProcessCertificateRequest(state, serverMessage.Body); /* * TODO Give the client a chance to immediately select the CertificateVerify hash * algorithm here to avoid tracking the other hash algorithms unnecessarily? */ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, state.certificateRequest.SupportedSignatureAlgorithms); serverMessage = handshake.ReceiveMessage(); } else { // Okay, CertificateRequest is optional } if (serverMessage.Type == HandshakeType.server_hello_done) { if (serverMessage.Body.Length != 0) { throw new TlsFatalAlert(AlertDescription.decode_error); } } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } handshake.HandshakeHash.SealHashAlgorithms(); IList clientSupplementalData = state.client.GetClientSupplementalData(); if (clientSupplementalData != null) { byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData); handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody); } if (state.certificateRequest != null) { state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest); /* * 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. */ Certificate clientCertificate = null; if (state.clientCredentials != null) { clientCertificate = state.clientCredentials.Certificate; } if (clientCertificate == null) { clientCertificate = Certificate.EmptyChain; } byte[] certificateBody = GenerateCertificate(clientCertificate); handshake.SendMessage(HandshakeType.certificate, certificateBody); } if (state.clientCredentials != null) { state.keyExchange.ProcessClientCredentials(state.clientCredentials); } else { state.keyExchange.SkipClientCredentials(); } byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state); handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody); TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish(); securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null); TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange); recordLayer.InitPendingEpoch(state.client.GetCipher()); if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials) { TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials; /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ SignatureAndHashAlgorithm signatureAndHashAlgorithm; byte[] hash; if (TlsUtilities.IsTlsV12(state.clientContext)) { signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm; if (signatureAndHashAlgorithm == null) { throw new TlsFatalAlert(AlertDescription.internal_error); } hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } else { signatureAndHashAlgorithm = null; hash = securityParameters.SessionHash; } byte[] signature = signerCredentials.GenerateCertificateSignature(hash); DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify); handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody); } // NOTE: Calculated exclusive of the Finished message itself byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); handshake.SendMessage(HandshakeType.finished, clientVerifyData); if (state.expectSessionTicket) { serverMessage = handshake.ReceiveMessage(); if (serverMessage.Type == HandshakeType.session_ticket) { ProcessNewSessionTicket(state, serverMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } } // NOTE: Calculated exclusive of the actual Finished message from the server byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData); handshake.Finish(); if (state.tlsSession != null) { state.sessionParameters = new SessionParameters.Builder() .SetCipherSuite(securityParameters.cipherSuite) .SetCompressionAlgorithm(securityParameters.compressionAlgorithm) .SetMasterSecret(securityParameters.masterSecret) .SetPeerCertificate(serverCertificate) .SetPskIdentity(securityParameters.pskIdentity) .Build(); state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); state.clientContext.SetResumableSession(state.tlsSession); } state.client.NotifyHandshakeComplete(); return(new DtlsTransport(recordLayer)); }
internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer) { SecurityParameters securityParameters = state.clientContext.SecurityParameters; DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer); byte[] clientHelloBody = GenerateClientHello(state, state.client); handshake.SendMessage(HandshakeType.client_hello, clientHelloBody); DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage(); while (serverMessage.Type == HandshakeType.hello_verify_request) { ProtocolVersion recordLayerVersion = recordLayer.ResetDiscoveredPeerVersion(); ProtocolVersion client_version = state.clientContext.ClientVersion; /* * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and * 1.0) and not as part of version negotiation. */ if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version)) throw new TlsFatalAlert(AlertDescription.illegal_parameter); byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body); byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie); handshake.ResetHandshakeMessagesDigest(); handshake.SendMessage(HandshakeType.client_hello, patched); serverMessage = handshake.ReceiveMessage(); } if (serverMessage.Type == HandshakeType.server_hello) { ReportServerVersion(state, recordLayer.DiscoveredPeerVersion); ProcessServerHello(state, serverMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } handshake.NotifyHelloComplete(); ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength); if (state.resumedSession) { securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret); recordLayer.InitPendingEpoch(state.client.GetCipher()); // NOTE: Calculated exclusive of the actual Finished message from the server byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData); // NOTE: Calculated exclusive of the Finished message itself byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); handshake.SendMessage(HandshakeType.finished, resClientVerifyData); handshake.Finish(); state.clientContext.SetResumableSession(state.tlsSession); state.client.NotifyHandshakeComplete(); return new DtlsTransport(recordLayer); } InvalidateSession(state); if (state.selectedSessionID.Length > 0) { state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null); } serverMessage = handshake.ReceiveMessage(); if (serverMessage.Type == HandshakeType.supplemental_data) { ProcessServerSupplementalData(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { state.client.ProcessServerSupplementalData(null); } state.keyExchange = state.client.GetKeyExchange(); state.keyExchange.Init(state.clientContext); Certificate serverCertificate = null; if (serverMessage.Type == HandshakeType.certificate) { serverCertificate = ProcessServerCertificate(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, Certificate is optional state.keyExchange.SkipServerCredentials(); } // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus if (serverCertificate == null || serverCertificate.IsEmpty) { state.allowCertificateStatus = false; } if (serverMessage.Type == HandshakeType.certificate_status) { ProcessCertificateStatus(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, CertificateStatus is optional } if (serverMessage.Type == HandshakeType.server_key_exchange) { ProcessServerKeyExchange(state, serverMessage.Body); serverMessage = handshake.ReceiveMessage(); } else { // Okay, ServerKeyExchange is optional state.keyExchange.SkipServerKeyExchange(); } if (serverMessage.Type == HandshakeType.certificate_request) { ProcessCertificateRequest(state, serverMessage.Body); /* * TODO Give the client a chance to immediately select the CertificateVerify hash * algorithm here to avoid tracking the other hash algorithms unnecessarily? */ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, state.certificateRequest.SupportedSignatureAlgorithms); serverMessage = handshake.ReceiveMessage(); } else { // Okay, CertificateRequest is optional } if (serverMessage.Type == HandshakeType.server_hello_done) { if (serverMessage.Body.Length != 0) { throw new TlsFatalAlert(AlertDescription.decode_error); } } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } handshake.HandshakeHash.SealHashAlgorithms(); IList clientSupplementalData = state.client.GetClientSupplementalData(); if (clientSupplementalData != null) { byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData); handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody); } if (state.certificateRequest != null) { state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest); /* * 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. */ Certificate clientCertificate = null; if (state.clientCredentials != null) { clientCertificate = state.clientCredentials.Certificate; } if (clientCertificate == null) { clientCertificate = Certificate.EmptyChain; } byte[] certificateBody = GenerateCertificate(clientCertificate); handshake.SendMessage(HandshakeType.certificate, certificateBody); } if (state.clientCredentials != null) { state.keyExchange.ProcessClientCredentials(state.clientCredentials); } else { state.keyExchange.SkipClientCredentials(); } byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state); handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody); TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish(); securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null); TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange); recordLayer.InitPendingEpoch(state.client.GetCipher()); if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials) { TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials; /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( state.clientContext, signerCredentials); byte[] hash; if (signatureAndHashAlgorithm == null) { hash = securityParameters.SessionHash; } else { hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } byte[] signature = signerCredentials.GenerateCertificateSignature(hash); DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify); handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody); } // NOTE: Calculated exclusive of the Finished message itself byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); handshake.SendMessage(HandshakeType.finished, clientVerifyData); if (state.expectSessionTicket) { serverMessage = handshake.ReceiveMessage(); if (serverMessage.Type == HandshakeType.session_ticket) { ProcessNewSessionTicket(state, serverMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } } // NOTE: Calculated exclusive of the actual Finished message from the server byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished, TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null)); ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData); handshake.Finish(); if (state.tlsSession != null) { state.sessionParameters = new SessionParameters.Builder() .SetCipherSuite(securityParameters.CipherSuite) .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm) .SetMasterSecret(securityParameters.MasterSecret) .SetPeerCertificate(serverCertificate) .SetPskIdentity(securityParameters.PskIdentity) .SetSrpIdentity(securityParameters.SrpIdentity) // TODO Consider filtering extensions that aren't relevant to resumed sessions .SetServerExtensions(state.serverExtensions) .Build(); state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); state.clientContext.SetResumableSession(state.tlsSession); } state.client.NotifyHandshakeComplete(); return new DtlsTransport(recordLayer); }