internal static TlsClientProtocol OpenTlsConnection(string hostname, int port, TlsClient client) { TcpClient tcp = new TcpClient(hostname, port); TlsClientProtocol protocol = new TlsClientProtocol(tcp.GetStream(), secureRandom); protocol.Connect(client); return protocol; }
public SecureTcpClient(string host, int port, TlsClient tlsClient) : base(AddressFamily.InterNetwork) { this.tlsClient = tlsClient; var myEndpoint = new DnsEndPoint(host, port); InnerConnect(myEndpoint); }
public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport) { if (client == null) throw new ArgumentNullException("client"); if (transport == null) throw new ArgumentNullException("transport"); SecurityParameters securityParameters = new SecurityParameters(); securityParameters.entity = ConnectionEnd.client; ClientHandshakeState state = new ClientHandshakeState(); state.client = client; state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters); securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(), state.clientContext.NonceRandomGenerator); client.Init(state.clientContext); DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake); TlsSession sessionToResume = state.client.GetSessionToResume(); if (sessionToResume != null && sessionToResume.IsResumable) { SessionParameters sessionParameters = sessionToResume.ExportSessionParameters(); if (sessionParameters != null) { state.tlsSession = sessionToResume; state.sessionParameters = sessionParameters; } } try { return ClientHandshake(state, recordLayer); } catch (TlsFatalAlert fatalAlert) { AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription); throw fatalAlert; } catch (IOException e) { AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (Exception e) { AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } finally { securityParameters.Clear(); } }
/** * 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 virtual void Connect(TlsClient tlsClient) { if (tlsClient == null) throw new ArgumentNullException("tlsClient"); if (this.mTlsClient != null) throw new InvalidOperationException("'Connect' can only be called once"); this.mTlsClient = tlsClient; this.mSecurityParameters = new SecurityParameters(); this.mSecurityParameters.entity = ConnectionEnd.client; this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters); this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(), mTlsClientContext.NonceRandomGenerator); this.mTlsClient.Init(mTlsClientContext); this.mRecordStream.Init(mTlsClientContext); TlsSession sessionToResume = tlsClient.GetSessionToResume(); if (sessionToResume != null && sessionToResume.IsResumable) { SessionParameters sessionParameters = sessionToResume.ExportSessionParameters(); if (sessionParameters != null) { this.mTlsSession = sessionToResume; this.mSessionParameters = sessionParameters; } } SendClientHelloMessage(); this.mConnectionState = CS_CLIENT_HELLO; CompleteHandshake(); }
private TlsClient InitializeTlsClient(string connectionString) { Dictionary <string, string> settings; string setting; SimplePolicyChecker certificateChecker; TlsClient remotingClient; SslProtocols enabledSslProtocols; SslPolicyErrors validPolicyErrors; X509ChainStatusFlags validChainFlags; // Initialize remoting client socket. certificateChecker = new SimplePolicyChecker(); remotingClient = new TlsClient(); remotingClient.ConnectionString = connectionString; remotingClient.PayloadAware = true; remotingClient.IgnoreInvalidCredentials = true; remotingClient.MaxConnectionAttempts = -1; remotingClient.RemoteCertificateValidationCallback = RemoteCertificateValidationCallback; remotingClient.CertificateChecker = certificateChecker; // Parse connection string into key-value pairs settings = connectionString.ParseKeyValuePairs(); // See if user wants to connect to remote service using integrated security if (settings.TryGetValue("integratedSecurity", out setting) && !string.IsNullOrWhiteSpace(setting)) { remotingClient.IntegratedSecurity = setting.ParseBoolean(); } // See if the user has explicitly defined the set of enabled SslProtocols try { if (settings.TryGetValue("enabledSslProtocols", out setting) && Enum.TryParse(setting, true, out enabledSslProtocols)) { remotingClient.EnabledSslProtocols = enabledSslProtocols; } else { remotingClient.EnabledSslProtocols = SslProtocols.Tls12; } } catch (SecurityException) { // Security exception can occur when user forces use of older TLS protocol through configuration but event log warning entry cannot be written } // See if the user has explicitly defined valid policy errors or valid chain flags if (settings.TryGetValue("validPolicyErrors", out setting) && Enum.TryParse(setting, true, out validPolicyErrors)) { certificateChecker.ValidPolicyErrors = validPolicyErrors; } else { certificateChecker.ValidPolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors; } if (settings.TryGetValue("validChainFlags", out setting) && Enum.TryParse(setting, true, out validChainFlags)) { certificateChecker.ValidChainFlags = validChainFlags; } else { certificateChecker.ValidChainFlags = X509ChainStatusFlags.UntrustedRoot; } // See if the user has explicitly defined whether to execute revocation checks on server certificates if (settings.TryGetValue("checkCertificateRevocation", out setting) && !string.IsNullOrWhiteSpace(setting)) { remotingClient.CheckCertificateRevocation = setting.ParseBoolean(); } return(remotingClient); }
private void CleanupClients(object state) { List <string> toRemove = new List <string>(); /* Scan for dead clients * According to MSDN, a client will be detected to be dead * only after a failed I/O. * If no messages run on channel, lots of dead clients won't be * discovered. This is why we force flushing the stream: if client * is dead, IOException is triggered and Connected is set to false */ _listLock.AcquireReaderLock(DEFAULT_JOIN_TIMEOUT); try { foreach (KeyValuePair <string, TlsClient> kvp in _clients) { try { kvp.Value.Stream.Flush(); } catch (IOException) { } //Flush did its real job if (!kvp.Value.Client.Connected) { toRemove.Add(kvp.Key); } } if (toRemove.Count > 0) { LockCookie ck = _listLock.UpgradeToWriterLock(DEFAULT_JOIN_TIMEOUT); try { foreach (string id in toRemove) { try { TlsClient client = _clients[id]; _clients.Remove(id); client.Dispose(); } catch (KeyNotFoundException ex) { //Strange Log.Debug("Error occurred when purging dead TLS client: {0}", ex.Message); } } } finally { _listLock.DowngradeFromWriterLock(ref ck); } } } finally { _listLock.ReleaseReaderLock(); } if (toRemove.Count > 0) { Log.Notice("TLS transport {0} cleaned up {1} dead clients", GetHashCode(), toRemove.Count); } }
private void DispatchLoop() { try { while (true) { SyslogMessage[] msgs = _queue.Flush(); if (msgs == null || msgs.Length == 0) { msgs = new[] { _queue.Dequeue() } } ; byte[] data; using (MemoryStream ms = new MemoryStream(8192)) { foreach (SyslogMessage msg in msgs) { byte[] payload = Encoding.UTF8.GetBytes(msg.ToRfc5424String()); foreach (char c in payload.Length.ToString(CultureInfo.InvariantCulture)) { ms.WriteByte((byte)c); } ms.WriteByte((byte)' '); ms.Write(payload, 0, payload.Length); _messagesSent++; } data = ms.ToArray(); } //Waiting for pending writes //Critical section. Obtain a snapshot of list and release lock ASAP TlsClient[] clients; _listLock.AcquireReaderLock(DEFAULT_JOIN_TIMEOUT); try { clients = new TlsClient[_clients.Count]; _clients.Values.CopyTo(clients, 0); } finally { _listLock.ReleaseReaderLock(); } foreach (TlsClient client in clients) { if (client.AsyncResult != null) { try { client.Stream.EndWrite(client.AsyncResult); client.AsyncResult = null; } catch (ObjectDisposedException) { } catch (IOException ex) { Log.Warning("Unable to send paylod to TLS client {0}", client.Client.Client.RemoteEndPoint.ToString()); Log.Debug("Error details: {0}", ex.Message); } } } foreach (TlsClient client in clients) { try { /* Asynchronously writing data to buffer. * Once writing is completed, the callback signals the AutoResetEvent * and once all clients signal the AutoResetEvent, new data will be written. * Meanwhile, TlsClient encodes new data to send */ client.AsyncResult = client.Stream.BeginWrite(data, 0, data.Length, null, null); } catch (IOException ex) { Log.Warning("Unable to send paylod to TLS client {0}", client.Client.Client.RemoteEndPoint.ToString()); Log.Debug("Error details: {0}", ex.Message); } catch (ObjectDisposedException) { } } } } catch (ThreadInterruptedException) { } catch (Exception ex) { Log.Error("Failed TLS cycle in SyslogTlsTransport"); Log.Debug("Error details: {0}", ex.Message); Dispose(); } }
/// <summary> /// Implements IOutboundTransport.SubscribeClient /// </summary> /// <remarks> /// Input instructions: (both required) /// <list> /// <item><c>host</c>: host name to connect to and validate certificate for</item> /// <item><c>port</c>: port number to use</item> /// <item><c>ip</c> (optional): overrides host, which is still required for certificate validation</item> /// </list> /// /// Output instructions: none /// </remarks> public string SubscribeClient(IEnumerable <KeyValuePair <string, string> > inputInstructions, out IEnumerable <KeyValuePair <string, string> > outputInstructions) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (inputInstructions == null) { throw new ArgumentNullException("inputInstructions"); } string host = null, portno = null; int port; IPAddress ipOverride = null; foreach (KeyValuePair <string, string> kvp in inputInstructions) { switch (kvp.Key) { case "host": { host = kvp.Value; break; } case "port": { portno = kvp.Value; break; } case "ip": { if (!IPAddress.TryParse(kvp.Value, out ipOverride)) { throw new TransportException("Invalid IP address specified"); } break; } } } //Parameter error detection if (host == null) { throw new TransportException("Host name not specified"); } if (portno == null) { throw new TransportException("Port number not specified"); } if (!int.TryParse(portno, out port)) { throw new TransportException("Invalid TCP port number"); } if (port < 1 || port > 65534) { throw new TransportException("Invalid TCP port number"); } outputInstructions = new Dictionary <string, string>(); try { TcpClient newTcpClient; if (ipOverride == null) { newTcpClient = new TcpClient(host, port); } else { newTcpClient = new TcpClient(ipOverride.AddressFamily) { NoDelay = true, SendBufferSize = 65536 }; newTcpClient.Connect(ipOverride, port); } SslStream sslStream = new SslStream(newTcpClient.GetStream(), false, RemoteCertificateValidation, LocalCertificateSelection); sslStream.AuthenticateAsClient(host); TlsClient newClient = new TlsClient(newTcpClient, sslStream); string id = newClient.GetHashCode().ToString(); _listLock.AcquireWriterLock(DEFAULT_JOIN_TIMEOUT); try { _clients.Add(id, newClient); return(id); } finally { _listLock.ReleaseWriterLock(); } } catch (Exception ex) { Log.Error("Unable to subscribe new TLS client"); Log.Debug("Error details: {0}", ex); throw new TransportException("Unable to subscribe client", ex); } }
public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport) { if (client == null) { throw new ArgumentNullException("client"); } if (transport == null) { throw new ArgumentNullException("transport"); } SecurityParameters securityParameters = new SecurityParameters(); securityParameters.entity = ConnectionEnd.client; ClientHandshakeState state = new ClientHandshakeState(); state.client = client; state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters); securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(), state.clientContext.NonceRandomGenerator); client.Init(state.clientContext); DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake); TlsSession sessionToResume = state.client.GetSessionToResume(); if (sessionToResume != null && sessionToResume.IsResumable) { SessionParameters sessionParameters = sessionToResume.ExportSessionParameters(); if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret) { state.tlsSession = sessionToResume; state.sessionParameters = sessionParameters; } } try { return(ClientHandshake(state, recordLayer)); } catch (TlsFatalAlert fatalAlert) { AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription); throw fatalAlert; } catch (IOException e) { AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (Exception e) { AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } finally { securityParameters.Clear(); } }
public virtual void Connect(TlsClient tlsClient) { if (tlsClient == null) { throw new ArgumentNullException("tlsClient"); } if (this.tlsClient != null) { throw new InvalidOperationException("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, 4, 28); TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0); this.tlsClientContext = new TlsClientContextImpl(random, securityParameters); this.tlsClient = tlsClient; this.tlsClient.Init(tlsClientContext); MemoryStream outStr = new MemoryStream(); TlsUtilities.WriteVersion(outStr); outStr.Write(securityParameters.clientRandom, 0, 32); /* * Length of Session id */ TlsUtilities.WriteUint8(0, outStr); this.offeredCipherSuites = this.tlsClient.GetCipherSuites(); // ExtensionType -> 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. */ bool noRenegExt = clientExtensions == null || !clientExtensions.Contains(ExtensionType.renegotiation_info); int count = offeredCipherSuites.Length; if (noRenegExt) { // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV ++count; } TlsUtilities.WriteUint16(2 * count, outStr); for (int i = 0; i < offeredCipherSuites.Length; ++i) { TlsUtilities.WriteUint16((int)offeredCipherSuites[i], outStr); } if (noRenegExt) { TlsUtilities.WriteUint16((int)CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr); } } /* * Compression methods, just the null method. */ this.offeredCompressionMethods = tlsClient.GetCompressionMethods(); { TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr); for (int i = 0; i < offeredCompressionMethods.Length; ++i) { TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr); } } // Extensions if (clientExtensions != null) { MemoryStream ext = new MemoryStream(); foreach (ExtensionType extType in clientExtensions.Keys) { WriteExtension(ext, extType, (byte[])clientExtensions[extType]); } TlsUtilities.WriteOpaque16(ext.ToArray(), outStr); } MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8((byte)HandshakeType.client_hello, bos); TlsUtilities.WriteUint24((int)outStr.Length, bos); byte[] outBytes = outStr.ToArray(); bos.Write(outBytes, 0, outBytes.Length); byte[] message = bos.ToArray(); 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.tlsStream = new TlsStream(this); }
/// <summary> /// Create a communications client /// </summary> /// <remarks> /// Note that typical connection string should be prefixed with a "protocol=tcp", "protocol=udp", "protocol=serial" or "protocol=file" /// </remarks> /// <returns>A communications client.</returns> /// <param name="connectionString">Connection string for the client.</param> public static IClient Create(string connectionString) { Dictionary <string, string> connectionSettings = connectionString.ParseKeyValuePairs(); IClient client; string protocol; if (connectionSettings.TryGetValue("protocol", out protocol)) { connectionSettings.Remove("protocol"); StringBuilder settings = new StringBuilder(); foreach (string key in connectionSettings.Keys) { settings.Append(key); settings.Append("="); settings.Append(connectionSettings[key]); settings.Append(";"); } // Create a client instance for the specified protocol. switch (protocol.Trim().ToLower()) { case "tls": client = new TlsClient(settings.ToString()); break; case "tcp": client = new TcpClient(settings.ToString()); break; case "udp": client = new UdpClient(settings.ToString()); break; case "file": client = new FileClient(settings.ToString()); break; case "serial": client = new SerialClient(settings.ToString()); break; default: throw new ArgumentException(protocol + " is not a valid transport protocol"); } // Apply client settings from the connection string to the client. foreach (KeyValuePair <string, string> setting in connectionSettings) { PropertyInfo property = client.GetType().GetProperty(setting.Key); if (property != null) { property.SetValue(client, Convert.ChangeType(setting.Value, property.PropertyType), null); } } } else { throw new ArgumentException("Transport protocol must be specified"); } return(client); }
internal static TlsClientProtocol OpenTlsConnection(string hostname, int port, TlsClient client) { TcpClient tcp = new TcpClient(hostname, port); TlsClientProtocol protocol = new TlsClientProtocol(tcp.GetStream(), secureRandom); protocol.Connect(client); return(protocol); }
protected virtual byte[] GenerateClientHello(DtlsClientProtocol.ClientHandshakeState state, TlsClient client) { MemoryStream memoryStream = new MemoryStream(); ProtocolVersion clientVersion = client.ClientVersion; if (!clientVersion.IsDtls) { throw new TlsFatalAlert(80); } TlsClientContextImpl clientContext = state.clientContext; clientContext.SetClientVersion(clientVersion); TlsUtilities.WriteVersion(clientVersion, memoryStream); SecurityParameters securityParameters = clientContext.SecurityParameters; memoryStream.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); byte[] array = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { array = state.tlsSession.SessionID; if (array == null || array.Length > 32) { array = TlsUtilities.EmptyBytes; } } TlsUtilities.WriteOpaque8(array, memoryStream); TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, memoryStream); bool isFallback = client.IsFallback; state.offeredCipherSuites = client.GetCipherSuites(); state.clientExtensions = client.GetClientExtensions(); byte[] extensionData = TlsUtilities.GetExtensionData(state.clientExtensions, 65281); bool flag = null == extensionData; bool flag2 = !Arrays.Contains(state.offeredCipherSuites, 255); if (flag && flag2) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, 255); } if (isFallback && !Arrays.Contains(state.offeredCipherSuites, 22016)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, 22016); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, memoryStream); byte[] offeredCompressionMethods = new byte[1]; state.offeredCompressionMethods = offeredCompressionMethods; TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, memoryStream); if (state.clientExtensions != null) { TlsProtocol.WriteExtensions(memoryStream, state.clientExtensions); } return(memoryStream.ToArray()); }
protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client) { MemoryStream buf = new MemoryStream(); ProtocolVersion client_version = client.ClientVersion; if (!client_version.IsDtls) throw new TlsFatalAlert(AlertDescription.internal_error); TlsClientContextImpl context = state.clientContext; context.SetClientVersion(client_version); TlsUtilities.WriteVersion(client_version, buf); SecurityParameters securityParameters = context.SecurityParameters; buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); // Session ID byte[] session_id = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { session_id = state.tlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } TlsUtilities.WriteOpaque8(session_id, buf); // Cookie TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf); bool fallback = client.IsFallback; /* * Cipher suites */ state.offeredCipherSuites = client.GetCipherSuites(); // Integer -> byte[] state.clientExtensions = client.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. */ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version * containing a lower value than the latest (highest-valued) version supported by the * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in * ClientHello.cipher_suites. */ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } // TODO Add support for compression // Compression methods // state.offeredCompressionMethods = client.getCompressionMethods(); state.offeredCompressionMethods = new byte[]{ CompressionMethod.cls_null }; TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf); // Extensions if (state.clientExtensions != null) { TlsProtocol.WriteExtensions(buf, state.clientExtensions); } return buf.ToArray(); }
/// <summary> /// Send a HTTP request to the remote socket /// </summary> /// <param name="method"></param> /// <param name="resource"></param> /// <param name="httpVersion"></param> /// <param name="client"></param> /// <param name="headers"></param> /// <returns>Response Stream</returns> public Stream SendHttp(string method, string resource, string data, string httpVersion, TlsClient client, HttpHeaders headers) { TlsClientProtocol protocol = new TlsClientProtocol(_tcpClient.GetStream(), new SecureRandom()); try { protocol.Connect(client); } catch (TlsException) { throw new ProtocolVersionNotSupported(); } // build protocol info, headers & body StringBuilder sb = new StringBuilder(); sb.AppendLine($"{method.ToUpper()} {resource} HTTP/{httpVersion}"); if (!headers.Contains("host")) { headers.Add("Host", _host); } sb.AppendLine(headers.ToString()); // append data in case of POST or similar if (data != null) { sb.Append(data); } // Console.WriteLine(sb.ToString()); var requestBytes = Encoding.ASCII.GetBytes(sb.ToString()); Stream stream = protocol.Stream; stream.Write(requestBytes, 0, requestBytes.Length); stream.Flush(); return(stream); }
// public void Connect(ICertificateVerifyer verifyer, Certificate clientCertificate, // AsymmetricKeyParameter clientPrivateKey) // { // DefaultTlsClient client = new DefaultTlsClient(verifyer); // client.EnableClientAuthentication(clientCertificate, clientPrivateKey); // // this.Connect(client); // } // TODO Make public internal virtual void Connect(TlsClient tlsClient) { if (tlsClient == null) throw new ArgumentNullException("tlsClient"); if (this.tlsClient != null) throw new InvalidOperationException("Connect can only be called once"); this.tlsClient = tlsClient; this.tlsClient.Init(this); /* * Send Client hello * * First, generate some random data. */ securityParameters = new SecurityParameters(); securityParameters.clientRandom = new byte[32]; random.NextBytes(securityParameters.clientRandom, 4, 28); TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0); MemoryStream outStr = new MemoryStream(); TlsUtilities.WriteVersion(outStr); outStr.Write(securityParameters.clientRandom, 0, 32); /* * Length of Session id */ TlsUtilities.WriteUint8((short)0, outStr); /* * Cipher suites */ this.offeredCipherSuites = this.tlsClient.GetCipherSuites(); // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV TlsUtilities.WriteUint16(2 * (offeredCipherSuites.Length + 1), outStr); for (int i = 0; i < offeredCipherSuites.Length; ++i) { TlsUtilities.WriteUint16(offeredCipherSuites[i], outStr); } // RFC 5746 3.3 // Note: If renegotiation added, remove this (and extra slot above) TlsUtilities.WriteUint16(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr); /* * Compression methods, just the null method. */ byte[] compressionMethods = new byte[]{0x00}; TlsUtilities.WriteOpaque8(compressionMethods, outStr); /* * Extensions */ // Int32 -> byte[] Hashtable clientExtensions = this.tlsClient.GenerateClientExtensions(); // RFC 5746 3.4 // Note: If renegotiation is implemented, need to use this instead of TLS_EMPTY_RENEGOTIATION_INFO_SCSV // { // if (clientExtensions == null) // clientExtensions = new Hashtable(); // // clientExtensions[EXT_RenegotiationInfo] = CreateRenegotiationInfo(emptybuf); // } this.extendedClientHello = clientExtensions != null && clientExtensions.Count > 0; if (extendedClientHello) { MemoryStream ext = new MemoryStream(); foreach (int extType in clientExtensions.Keys) { byte[] extValue = (byte[])clientExtensions[extType]; TlsUtilities.WriteUint16(extType, ext); TlsUtilities.WriteOpaque16(extValue, ext); } TlsUtilities.WriteOpaque16(ext.ToArray(), outStr); } MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); TlsUtilities.WriteUint24((int) outStr.Length, bos); byte[] outBytes = outStr.ToArray(); bos.Write(outBytes, 0, outBytes.Length); byte[] message = bos.ToArray(); rs.WriteMessage(RL_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) { // TODO Should we send fatal alerts in the event of an exception // (see readApplicationData) rs.ReadData(); } this.tlsStream = new TlsStream(this); }
protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client) { MemoryStream buf = new MemoryStream(); ProtocolVersion client_version = client.ClientVersion; if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } TlsClientContextImpl context = state.clientContext; context.SetClientVersion(client_version); TlsUtilities.WriteVersion(client_version, buf); SecurityParameters securityParameters = context.SecurityParameters; buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); // Session ID byte[] session_id = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { session_id = state.tlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } TlsUtilities.WriteOpaque8(session_id, buf); // Cookie TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf); bool fallback = client.IsFallback; /* * Cipher suites */ state.offeredCipherSuites = client.GetCipherSuites(); // Integer -> byte[] state.clientExtensions = client.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. */ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version * containing a lower value than the latest (highest-valued) version supported by the * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in * ClientHello.cipher_suites. */ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } // TODO Add support for compression // Compression methods // state.offeredCompressionMethods = client.getCompressionMethods(); state.offeredCompressionMethods = new byte[] { CompressionMethod.cls_null }; TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf); // Extensions if (state.clientExtensions != null) { TlsProtocol.WriteExtensions(buf, state.clientExtensions); } return(buf.ToArray()); }
// public void Connect(ICertificateVerifyer verifyer, Certificate clientCertificate, // AsymmetricKeyParameter clientPrivateKey) // { // DefaultTlsClient client = new DefaultTlsClient(verifyer); // client.EnableClientAuthentication(clientCertificate, clientPrivateKey); // // this.Connect(client); // } // TODO Make public internal virtual void Connect(TlsClient tlsClient) { if (tlsClient == null) { throw new ArgumentNullException("tlsClient"); } if (this.tlsClient != null) { throw new InvalidOperationException("Connect can only be called once"); } this.tlsClient = tlsClient; this.tlsClient.Init(this); /* * Send Client hello * * First, generate some random data. */ securityParameters = new SecurityParameters(); securityParameters.clientRandom = new byte[32]; random.NextBytes(securityParameters.clientRandom, 4, 28); TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0); MemoryStream outStr = new MemoryStream(); TlsUtilities.WriteVersion(outStr); outStr.Write(securityParameters.clientRandom, 0, 32); /* * Length of Session id */ TlsUtilities.WriteUint8((short)0, outStr); /* * Cipher suites */ this.offeredCipherSuites = this.tlsClient.GetCipherSuites(); // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV TlsUtilities.WriteUint16(2 * (offeredCipherSuites.Length + 1), outStr); for (int i = 0; i < offeredCipherSuites.Length; ++i) { TlsUtilities.WriteUint16(offeredCipherSuites[i], outStr); } // RFC 5746 3.3 // Note: If renegotiation added, remove this (and extra slot above) TlsUtilities.WriteUint16(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr); /* * Compression methods, just the null method. */ byte[] compressionMethods = new byte[] { 0x00 }; TlsUtilities.WriteOpaque8(compressionMethods, outStr); /* * Extensions */ // Int32 -> byte[] Hashtable clientExtensions = this.tlsClient.GenerateClientExtensions(); // RFC 5746 3.4 // Note: If renegotiation is implemented, need to use this instead of TLS_EMPTY_RENEGOTIATION_INFO_SCSV // { // if (clientExtensions == null) // clientExtensions = new Hashtable(); // // clientExtensions[EXT_RenegotiationInfo] = CreateRenegotiationInfo(emptybuf); // } this.extendedClientHello = clientExtensions != null && clientExtensions.Count > 0; if (extendedClientHello) { MemoryStream ext = new MemoryStream(); foreach (int extType in clientExtensions.Keys) { byte[] extValue = (byte[])clientExtensions[extType]; TlsUtilities.WriteUint16(extType, ext); TlsUtilities.WriteOpaque16(extValue, ext); } TlsUtilities.WriteOpaque16(ext.ToArray(), outStr); } MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); TlsUtilities.WriteUint24((int)outStr.Length, bos); byte[] outBytes = outStr.ToArray(); bos.Write(outBytes, 0, outBytes.Length); byte[] message = bos.ToArray(); rs.WriteMessage(RL_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) { // TODO Should we send fatal alerts in the event of an exception // (see readApplicationData) rs.ReadData(); } this.tlsStream = new TlsStream(this); }
public virtual void Connect(TlsClient tlsClient) { if (tlsClient == null) throw new ArgumentNullException("tlsClient"); if (this.tlsClient != null) throw new InvalidOperationException("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, 4, 28); TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0); this.tlsClientContext = new TlsClientContextImpl(random, securityParameters); this.tlsClient = tlsClient; this.tlsClient.Init(tlsClientContext); MemoryStream outStr = new MemoryStream(); TlsUtilities.WriteVersion(outStr); outStr.Write(securityParameters.clientRandom, 0, 32); /* * Length of Session id */ TlsUtilities.WriteUint8(0, outStr); this.offeredCipherSuites = this.tlsClient.GetCipherSuites(); // ExtensionType -> 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. */ bool noRenegExt = clientExtensions == null || !clientExtensions.Contains(ExtensionType.renegotiation_info); int count = offeredCipherSuites.Length; if (noRenegExt) { // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV ++count; } TlsUtilities.WriteUint16(2 * count, outStr); for (int i = 0; i < offeredCipherSuites.Length; ++i) { TlsUtilities.WriteUint16((int)offeredCipherSuites[i], outStr); } if (noRenegExt) { TlsUtilities.WriteUint16((int)CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr); } } /* * Compression methods, just the null method. */ this.offeredCompressionMethods = tlsClient.GetCompressionMethods(); { TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr); for (int i = 0; i < offeredCompressionMethods.Length; ++i) { TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr); } } // Extensions if (clientExtensions != null) { MemoryStream ext = new MemoryStream(); foreach (ExtensionType extType in clientExtensions.Keys) { WriteExtension(ext, extType, (byte[])clientExtensions[extType]); } TlsUtilities.WriteOpaque16(ext.ToArray(), outStr); } MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8((byte)HandshakeType.client_hello, bos); TlsUtilities.WriteUint24((int)outStr.Length, bos); byte[] outBytes = outStr.ToArray(); bos.Write(outBytes, 0, outBytes.Length); byte[] message = bos.ToArray(); 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.tlsStream = new TlsStream(this); }
protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client) { ProtocolVersion client_version = client.ClientVersion; if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } TlsClientContextImpl context = state.clientContext; context.SetClientVersion(client_version); SecurityParameters securityParameters = context.SecurityParameters; // Session ID byte[] session_id = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { session_id = state.tlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } bool fallback = client.IsFallback; state.offeredCipherSuites = client.GetCipherSuites(); if (session_id.Length > 0 && state.sessionParameters != null) { if (!state.sessionParameters.IsExtendedMasterSecret || !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite) || CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm) { session_id = TlsUtilities.EmptyBytes; } } state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions()); TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions); MemoryStream buf = new MemoryStream(); TlsUtilities.WriteVersion(client_version, buf); buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); TlsUtilities.WriteOpaque8(session_id, buf); // Cookie TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf); // 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 = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value * than the latest (highest-valued) version supported by the client, it SHOULD include * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends * to negotiate.) */ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[] { CompressionMethod.cls_null }, buf); TlsProtocol.WriteExtensions(buf, state.clientExtensions); return(buf.ToArray()); }