public AsyncDtlsClientProtocol(AsyncDtlsClient client, SecureRandom secureRandom, IChannel channel, HandshakeHandler parentHandler, DtlsStateHandler handler, Boolean useExtendedMasterSecret, ProtocolVersion initialVersion) { this.parentHandler = parentHandler; this.handler = handler; this.channel = channel; this.protocolVersion = initialVersion; AsyncDtlsSecurityParameters securityParameters = new AsyncDtlsSecurityParameters(); securityParameters.SetEntity(ConnectionEnd.client); clientState = new AsyncDtlsClientState(); clientState.Client = client; clientState.ClientContext = new AsyncDtlsClientContext(secureRandom, securityParameters); securityParameters.SetExtendedMasterSecret(useExtendedMasterSecret); securityParameters.SetClientRandom(DtlsHelper.CreateRandomBlock(client.ShouldUseGmtUnixTime(), clientState.ClientContext.NonceRandomGenerator)); client.InitClient(clientState.ClientContext); clientState.HandshakeHash = new DeferredHash(); clientState.HandshakeHash.Init(clientState.ClientContext); recordLayer = new AsyncDtlsRecordLayer(clientState.HandshakeHash, this, channel, clientState.ClientContext, client); }
public AsyncDtlsClientContext(SecureRandom secureRandom, AsyncDtlsSecurityParameters securityParameters) { IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256); byte[] seed = new byte[d.GetDigestSize()]; secureRandom.NextBytes(seed); this.nonceRandom = new DigestRandomGenerator(d); nonceRandom.AddSeedMaterial(NextCounterValue()); nonceRandom.AddSeedMaterial(Times.NanoTime()); nonceRandom.AddSeedMaterial(seed); this.secureRandom = secureRandom; this.securityParameters = securityParameters; }
public void PostProcessFinished() { if (handshakeState == State.SERVER_HELLO_RECEIVED) { byte[] clientVerifyData = DtlsHelper.CalculateVerifyData(clientState.ClientContext, ExporterLabel.client_finished, DtlsHelper.GetCurrentPRFHash(clientState.ClientContext, clientState.HandshakeHash, null)); IByteBuffer serverVerifyBuffer = Unpooled.Buffer(DtlsHelper.HANDSHAKE_MESSAGE_HEADER_LENGTH + clientVerifyData.Length); short currSequence = sequence++; DtlsHelper.WriteHandshakeHeader(currSequence, MessageType.FINISHED, serverVerifyBuffer, clientVerifyData.Length); serverVerifyBuffer.WriteBytes(clientVerifyData); recordLayer.Send(currSequence, MessageType.FINISHED, serverVerifyBuffer); } recordLayer.HandshakeSuccessful(); if (handshakeState == State.SERVER_HELLO_RECEIVED) { clientState.ClientContext.ResumableSession = clientState.TlsSession; } else { if (clientState.TlsSession != null) { AsyncDtlsSecurityParameters parameters = (AsyncDtlsSecurityParameters)clientState.ClientContext.SecurityParameters; clientState.SessionParameters = new SessionParameters.Builder() .SetCipherSuite(parameters.CipherSuite) .SetCompressionAlgorithm(parameters.CompressionAlgorithm) .SetMasterSecret(parameters.MasterSecret) .SetPeerCertificate(serverCertificate) .SetPskIdentity(parameters.PskIdentity) .SetSrpIdentity(parameters.SrpIdentity) .SetServerExtensions(clientState.ServerExtensions) .Build(); clientState.TlsSession = new AsyncDtlsSessionImpl(clientState.TlsSession.SessionID, clientState.SessionParameters); clientState.ClientContext.ResumableSession = clientState.TlsSession; } } clientState.Client.NotifyHandshakeComplete(); }
private void ProcessServerHello(IByteBuffer body) { ProtocolVersion recordLayerVersion = recordLayer.GetReadVersion(); ReportServerVersion(recordLayerVersion); recordLayer.SetWriteVersion(recordLayerVersion); AsyncDtlsSecurityParameters securityParameters = (AsyncDtlsSecurityParameters)clientState.ClientContext.SecurityParameters; ProtocolVersion server_version = ProtocolVersion.Get(body.ReadByte() & 0xFF, body.ReadByte() & 0xFF); ReportServerVersion(server_version); byte[] serverRandom = new byte[32]; body.ReadBytes(serverRandom); securityParameters.SetServerRandom(serverRandom); byte[] selectedSessionID = new byte[body.ReadByte() & 0x0FF]; if (selectedSessionID.Length > 0) { body.ReadBytes(selectedSessionID); } clientState.SelectedSessionID = selectedSessionID; if (selectedSessionID.Length > 32) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } clientState.Client.NotifySessionID(selectedSessionID); clientState.ResumedSession = selectedSessionID.Length > 0 && clientState.TlsSession != null && ArrayUtils.Equals(clientState.SelectedSessionID, clientState.TlsSession.SessionID); int selectedCipherSuite = body.ReadUnsignedShort(); Boolean inOfferedCipherSuites = false; for (int i = 0; i < clientState.OfferedCipherSuites.Length; i++) { if (selectedCipherSuite == clientState.OfferedCipherSuites[i]) { inOfferedCipherSuites = true; break; } } if (!inOfferedCipherSuites || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(selectedCipherSuite) || !DtlsHelper.GetMinimumVersion(selectedCipherSuite).IsEqualOrEarlierVersionOf(clientState.ClientContext.ServerVersion.GetEquivalentTLSVersion())) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } switch (DtlsHelper.GetEncryptionAlgorithm(selectedCipherSuite)) { case EncryptionAlgorithm.RC4_40: case EncryptionAlgorithm.RC4_128: throw new TlsFatalAlert(AlertDescription.internal_error); } clientState.Client.NotifySelectedCipherSuite(selectedCipherSuite); byte selectedCompressionMethod = body.ReadByte(); Boolean inOfferedCompressionMethods = false; for (int i = 0; i < clientState.OfferedCompressionMethods.Length; i++) { if (selectedCompressionMethod == clientState.OfferedCompressionMethods[i]) { inOfferedCompressionMethods = true; break; } } if (!inOfferedCompressionMethods) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } clientState.Client.NotifySelectedCompressionMethod(selectedCompressionMethod); clientState.ServerExtensions = DtlsHelper.ReadSelectedExtensions(body); if (clientState.ServerExtensions != null) { foreach (Int32 extType in clientState.ServerExtensions.Keys) { if (extType.Equals(DtlsHelper.EXT_RenegotiationInfo)) { continue; } if (!clientState.ClientExtensions.Contains(extType)) { throw new TlsFatalAlert(AlertDescription.unsupported_extension); } } } byte[] renegExtData = null; if (clientState.ServerExtensions.Contains(DtlsHelper.EXT_RenegotiationInfo)) { renegExtData = (byte[])clientState.ServerExtensions[DtlsHelper.EXT_RenegotiationInfo]; } if (renegExtData != null) { clientState.SecureRenegotiation = true; if (!ArrayUtils.Equals(renegExtData, DtlsHelper.EMPTY_BYTES_WITH_LENGTH)) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } } if (clientState.SecureRenegotiation) { clientState.Client.NotifySecureRenegotiation(clientState.SecureRenegotiation); } IDictionary sessionClientExtensions = clientState.ClientExtensions; IDictionary sessionServerExtensions = clientState.ServerExtensions; if (clientState.ResumedSession) { if (selectedCipherSuite != clientState.SessionParameters.CipherSuite || selectedCompressionMethod != clientState.SessionParameters.CompressionAlgorithm) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } sessionClientExtensions = null; sessionServerExtensions = (Dictionary <Int32, byte[]>)clientState.SessionParameters.ReadServerExtensions(); } securityParameters.SetCipherSuite(selectedCipherSuite); securityParameters.SetCompressionAlgorithm(selectedCompressionMethod); if (sessionServerExtensions != null) { byte[] encryptThenMac = null; if (sessionServerExtensions.Contains(DtlsHelper.EXT_encrypt_then_mac)) { encryptThenMac = (byte[])sessionServerExtensions[DtlsHelper.EXT_encrypt_then_mac]; } if (encryptThenMac != null && encryptThenMac.Length > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } Boolean serverSentEncryptThenMAC = encryptThenMac != null; if (serverSentEncryptThenMAC && DtlsHelper.GetCipherType(securityParameters.CipherSuite) != CipherType.block) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } securityParameters.SetEncryptThenMAC(serverSentEncryptThenMAC); byte[] extendedMacSecret = null; if (sessionServerExtensions.Contains(DtlsHelper.EXT_extended_master_secret)) { extendedMacSecret = (byte[])sessionServerExtensions[DtlsHelper.EXT_extended_master_secret]; } if (extendedMacSecret != null && extendedMacSecret.Length > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } securityParameters.SetExtendedMasterSecret(extendedMacSecret != null); securityParameters.SetMaxFragmentLength(DtlsHelper.EvaluateMaxFragmentLengthExtension(clientState.ResumedSession, sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter)); byte[] truncatedHMAC = null; if (sessionServerExtensions.Contains(DtlsHelper.EXT_truncated_hmac)) { truncatedHMAC = (byte[])sessionServerExtensions[DtlsHelper.EXT_truncated_hmac]; } if (truncatedHMAC != null && truncatedHMAC.Length > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } securityParameters.SetTruncatedHMac(truncatedHMAC != null); byte[] statusRequest = null; if (sessionServerExtensions.Contains(DtlsHelper.EXT_status_request)) { statusRequest = (byte[])sessionServerExtensions[DtlsHelper.EXT_status_request]; } if (statusRequest != null && statusRequest.Length > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } clientState.AllowCertificateStatus = (!clientState.ResumedSession && statusRequest != null); byte[] sessionTicket = null; if (sessionServerExtensions.Contains(DtlsHelper.EXT_SessionTicket)) { sessionTicket = (byte[])sessionServerExtensions[DtlsHelper.EXT_SessionTicket]; } if (sessionTicket != null && sessionTicket.Length > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } clientState.ExpectSessionTicket = (!clientState.ResumedSession && sessionTicket != null); } if (sessionClientExtensions != null) { clientState.Client.ProcessServerExtensions(sessionServerExtensions); } securityParameters.SetPrfAlgorithm(DtlsHelper.GetPRFAlgorithm(clientState.ClientContext.ServerVersion, securityParameters.CipherSuite)); securityParameters.SetVerifyDataLength(12); }
public void InitHandshake(byte[] cookie) { AsyncDtlsSecurityParameters securityParameters = (AsyncDtlsSecurityParameters)clientState.ClientContext.SecurityParameters; ProtocolVersion client_version = clientState.Client.ClientVersion; if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } AsyncDtlsClientContext context = clientState.ClientContext; context.ClientVersion = client_version; Boolean fallback = clientState.Client.IsFallback; //Cipher suites clientState.OfferedCipherSuites = clientState.Client.GetCipherSuites(); // Integer -> byte[] clientState.ClientExtensions = clientState.Client.GetClientExtensions(); if (securityParameters.IsExtendedMasterSecret()) { if (clientState.ClientExtensions == null) { clientState.ClientExtensions = new Dictionary <int, byte[]>(); } clientState.ClientExtensions[DtlsHelper.EXT_extended_master_secret] = DtlsHelper.EMPTY_BYTES; } byte[] renegExtData = null; if (clientState.ClientExtensions.Contains(DtlsHelper.EXT_RenegotiationInfo)) { renegExtData = (byte[])clientState.ClientExtensions[DtlsHelper.EXT_RenegotiationInfo]; } Boolean noRenegExt = (null == renegExtData); Boolean noRenegSCSV = true; for (int i = 0; i < clientState.OfferedCipherSuites.Length; i++) { if (clientState.OfferedCipherSuites[i] == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { noRenegSCSV = false; break; } } Boolean tlsFallbackFound = false; for (int i = 0; i < clientState.OfferedCipherSuites.Length; i++) { if (clientState.OfferedCipherSuites[i] == CipherSuite.TLS_FALLBACK_SCSV) { tlsFallbackFound = true; break; } } int additionalCount = 0; if (noRenegExt && noRenegSCSV) { additionalCount++; } if (fallback && !tlsFallbackFound) { additionalCount++; } int[] offeredCipherSuites = clientState.OfferedCipherSuites; if (additionalCount > 0) { offeredCipherSuites = new int[clientState.OfferedCipherSuites.Length + additionalCount]; Array.Copy(clientState.OfferedCipherSuites, 0, offeredCipherSuites, 0, clientState.OfferedCipherSuites.Length); if (noRenegExt && noRenegSCSV) { offeredCipherSuites[clientState.OfferedCipherSuites.Length] = CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV; } if (fallback && !tlsFallbackFound) { offeredCipherSuites[offeredCipherSuites.Length - 1] = CipherSuite.TLS_FALLBACK_SCSV; } } clientState.OfferedCompressionMethods = new short[] { CompressionMethod.cls_null }; byte[] session_id = DtlsHelper.EMPTY_BYTES; if (clientState.TlsSession != null) { session_id = clientState.TlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = DtlsHelper.EMPTY_BYTES; } } int totalLength = 2; totalLength += securityParameters.ClientRandom.Length; totalLength += 1 + session_id.Length; if (cookie != null) { totalLength += cookie.Length + 1; } else { totalLength += 1; } totalLength += 2 + 2 * offeredCipherSuites.Length; totalLength += 1 + clientState.OfferedCompressionMethods.Length; totalLength += DtlsHelper.CalculateExtensionsLength(clientState.ClientExtensions); int capacity = DtlsHelper.HANDSHAKE_MESSAGE_HEADER_LENGTH + totalLength; IByteBuffer data = Unpooled.Buffer(capacity); short currSequence = sequence++; DtlsHelper.WriteHandshakeHeader(currSequence, MessageType.CLIENT_HELLO, data, totalLength); data.WriteByte(client_version.MajorVersion); data.WriteByte(client_version.MinorVersion); data.WriteBytes(securityParameters.ClientRandom); // Session ID data.WriteByte(session_id.Length); data.WriteBytes(session_id); //Cookie if (cookie != null) { data.WriteByte(cookie.Length); data.WriteBytes(cookie); } else { data.WriteBytes(DtlsHelper.EMPTY_BYTES_WITH_LENGTH); } data.WriteShort(2 * offeredCipherSuites.Length); for (int i = 0; i < offeredCipherSuites.Length; i++) { data.WriteShort(offeredCipherSuites[i]); } data.WriteByte(clientState.OfferedCompressionMethods.Length); for (int i = 0; i < clientState.OfferedCompressionMethods.Length; i++) { data.WriteByte(clientState.OfferedCompressionMethods[i]); } // Extensions if (clientState.ClientExtensions != null) { DtlsHelper.WriteExtensions(data, clientState.ClientExtensions); } if (protocolVersion == null) { recordLayer.SetWriteVersion(ProtocolVersion.DTLSv10); } else { recordLayer.SetWriteVersion(protocolVersion); } recordLayer.Send(currSequence, MessageType.CLIENT_HELLO, data); handshakeState = State.CLIENT_HELLO_SENT; if (handler != null) { handler.handshakeStarted(channel); } }