private void ListenLoop() { if (scheduler.Verbose) { Console.WriteLine("Starting to listen on {0}", myEndpoint); } listener = new TcpListener(myEndpoint); listener.ExclusiveAddressUse = true; listener.Start(); while (true) { if (scheduler.Verbose) { Console.WriteLine("Waiting for the next incoming connection"); } TcpClient client = listener.AcceptTcpClient(); CertificateValidator myValidator = new CertificateValidator(scheduler); SslStream sslStream = new SslStream(client.GetStream(), leaveInnerStreamOpen: false, myValidator.ValidateSSLCertificate); sslStream.AuthenticateAsServer(scheduler.MyCert, clientCertificateRequired: true, checkCertificateRevocation: false); var remoteCert = sslStream.RemoteCertificate as X509Certificate2; if (scheduler.Verbose) { Console.WriteLine("Received an incoming connection from remote certified as {0}", IoScheduler.CertificateToString(remoteCert)); } ReceiverThread.Create(scheduler, sslStream); ServerSenderThread.Create(scheduler, sslStream); } }
private void SendDispatchLoop() { while (true) { if (scheduler.Verbose) { Console.WriteLine("Waiting for the next send to dispatch"); } SendTask sendTask = sendQueue.Receive(); if (scheduler.Verbose) { Console.WriteLine("Dispatching send of message of size {0} to {1}", sendTask.Message.Length, IoScheduler.PublicKeyToString(sendTask.DestinationPublicKey)); } SenderThread senderThread = scheduler.FindSenderForDestinationPublicKey(sendTask.DestinationPublicKey); if (senderThread == null) { senderThread = ClientSenderThread.Create(scheduler, sendTask.DestinationPublicKey); } senderThread.EnqueueSendTask(sendTask); } }
public static ReceiverThread Create(IoScheduler scheduler, SslStream stream) { ReceiverThread receiverThread = new ReceiverThread(scheduler, stream); Thread t = new Thread(receiverThread.Run); t.Start(); return(receiverThread); }
protected SenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKey, SslStream i_stream, X509Certificate2 i_remoteCert) { scheduler = i_scheduler; destinationPublicKey = i_destinationPublicKey; stream = i_stream; remoteCert = i_remoteCert; sendQueue = new BufferBlock <SendTask>(); currentSendTask = null; }
public void Run() { try { ReceiveLoop(); } catch (Exception e) { scheduler.ReportException(e, "receiving from " + IoScheduler.GetCertificatePublicKey(remoteCert)); } }
public static ClientSenderThread Create(IoScheduler scheduler, byte[] destinationPublicKey) { if (scheduler.Verbose) { Console.WriteLine("Creating sender thread to send to remote public key {0}", scheduler.LookupPublicKeyAsString(destinationPublicKey)); } ClientSenderThread senderThread = new ClientSenderThread(scheduler, destinationPublicKey); senderThread.Start(); return(senderThread); }
private void StartServer(PrivateIdentity myIdentity, string localHostNameOrAddress, int localPort) { onlyClient = false; try { myCert = new X509Certificate2(myIdentity.Pkcs12, "" /* empty password */, X509KeyStorageFlags.Exportable); } catch (Exception e) { Console.Error.WriteLine("Could not import private key. Exception:{0}", e); throw new Exception("Can't start server because private key not decryptable"); } // The `local` parameters override the parameters in // `myIdentity`, unless they're empty or zero. if (localHostNameOrAddress == null || localHostNameOrAddress.Length == 0) { localHostNameOrAddress = myIdentity.HostNameOrAddress; } if (localPort == 0) { localPort = myIdentity.Port; } var address = LookupHostNameOrAddress(localHostNameOrAddress); if (address == null) { Console.Error.WriteLine("ERROR: Could not find any addresses when resolving {0}, which I'm supposed to bind to."); throw new Exception("Can't resolve binding address"); } var myEndpoint = new IPEndPoint(address, localPort); if (verbose) { Console.WriteLine("Starting I/O scheduler as server listening to {0} certified as {1}", myEndpoint, IoScheduler.CertificateToString(myCert)); } sendDispatchThread = new SendDispatchThread(this); Thread st = new Thread(sendDispatchThread.Run); st.Start(); // Start a thread to listen on my binding endpoint. listenerThread = new ListenerThread(this, myEndpoint); Thread lt = new Thread(listenerThread.Run); lt.Start(); }
public static IoScheduler CreateClient(List <PublicIdentity> serverIdentities, bool verbose = false, bool connectToAllServers = true, int maxSendTries = 3) { var scheduler = new IoScheduler(null, null, 0, serverIdentities, verbose, maxSendTries); if (connectToAllServers) { foreach (var serverIdentity in serverIdentities) { scheduler.Connect(serverIdentity.PublicKey); } } return(scheduler); }
private void ReceiveLoop() { bool success; if (scheduler.Verbose) { Console.WriteLine("Starting receive loop with remote identified as {0}", IoScheduler.CertificateToString(remoteCert)); } while (true) { // Read the next message's size. UInt64 messageSize; success = IoEncoder.ReadUInt64(stream, out messageSize); if (!success) { if (scheduler.Verbose) { Console.Error.WriteLine("Failed to receive message size from {0}", IoScheduler.CertificateToString(remoteCert)); } return; } if (scheduler.Verbose) { Console.WriteLine("Received message size {0} from {1}", messageSize, IoScheduler.CertificateToString(remoteCert)); } byte[] messageBuf = new byte[messageSize]; success = IoEncoder.ReadBytes(stream, messageBuf, 0, messageSize); if (!success) { if (scheduler.Verbose) { Console.Error.WriteLine("Failed to receive message of size {0} from {1}", messageSize, IoScheduler.CertificateToString(remoteCert)); } return; } if (scheduler.Verbose) { Console.WriteLine("Received message of size {0} from {1}", messageSize, IoScheduler.CertificateToString(remoteCert)); } ReceivedPacket packet = new ReceivedPacket(remoteCert, messageBuf); scheduler.NoteReceivedPacket(packet); } }
public static ServerSenderThread Create(IoScheduler scheduler, SslStream stream) { var remoteCert = stream.RemoteCertificate as X509Certificate2; var destinationPublicKey = IoScheduler.GetCertificatePublicKey(remoteCert); if (scheduler.Verbose) { Console.WriteLine("Creating sender thread to send to remote certified as {0}", IoScheduler.CertificateToString(remoteCert)); } ServerSenderThread senderThread = new ServerSenderThread(scheduler, destinationPublicKey, stream, remoteCert); senderThread.Start(); return(senderThread); }
/////////////////////////////////// // API for IoNative.cs /////////////////////////////////// public void ReceivePacket(Int32 timeLimit, out bool ok, out bool timedOut, out byte[] remotePublicKey, out byte[] message) { ReceivedPacket packet; try { if (timeLimit == 0) { timedOut = !receiveQueue.TryReceive(out packet); } else { TimeSpan timeSpan = TimeSpan.FromMilliseconds(timeLimit); packet = receiveQueue.Receive(timeSpan); timedOut = false; } ok = true; if (timedOut) { remotePublicKey = null; message = null; } else { remotePublicKey = IoScheduler.GetCertificatePublicKey(packet.SenderCert); message = packet.Message; if (verbose) { Console.WriteLine("Dequeueing a packet of size {0} from {1}", message.Length, CertificateToString(packet.SenderCert)); } } } catch (TimeoutException) { remotePublicKey = null; message = null; ok = true; timedOut = true; } catch (Exception e) { Console.Error.WriteLine("Unexpected error trying to read packet from packet queue. Exception:\n{0}", e); remotePublicKey = null; message = null; ok = false; timedOut = false; } }
private void StartClient() { onlyClient = true; myCert = IronfleetCrypto.CreateTransientClientIdentity(); if (verbose) { Console.WriteLine("Starting I/O scheduler as client with certificate {0}", IoScheduler.CertificateToString(myCert)); } sendDispatchThread = new SendDispatchThread(this); Thread st = new Thread(sendDispatchThread.Run); st.Start(); }
public static void CreateNewIdentity(string friendlyName, string hostNameOrAddress, int port, out PublicIdentity publicIdentity, out PrivateIdentity privateIdentity) { var key = RSA.Create(4096); var subject = string.Format("CN = {0}", friendlyName); var req = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); var now = DateTime.Now; var expiry = now.AddYears(10); var cert = req.CreateSelfSigned(now, expiry); var pkcs12 = cert.Export(X509ContentType.Pkcs12, "" /* empty password */); publicIdentity = new PublicIdentity { FriendlyName = friendlyName, PublicKey = IoScheduler.GetCertificatePublicKey(cert), HostNameOrAddress = hostNameOrAddress, Port = port }; privateIdentity = new PrivateIdentity { FriendlyName = friendlyName, Pkcs12 = pkcs12, HostNameOrAddress = hostNameOrAddress, Port = port }; }
public SendDispatchThread(IoScheduler i_scheduler) { scheduler = i_scheduler; sendQueue = new BufferBlock <SendTask>(); }
public ListenerThread(IoScheduler i_scheduler, IPEndPoint i_myEndpoint) { scheduler = i_scheduler; myEndpoint = i_myEndpoint; }
protected override bool Connect() { var destinationPublicIdentity = scheduler.LookupPublicKey(destinationPublicKey); if (destinationPublicIdentity == null) { if (scheduler.Verbose) { Console.Error.WriteLine("Could not connect to destination public key {0} because we don't know its address.", IoScheduler.PublicKeyToString(destinationPublicKey)); } return(false); } if (scheduler.Verbose) { Console.WriteLine("Starting connection to {0}", IoScheduler.PublicIdentityToString(destinationPublicIdentity)); } TcpClient client; try { client = new TcpClient(destinationPublicIdentity.HostNameOrAddress, destinationPublicIdentity.Port); } catch (Exception e) { scheduler.ReportException(e, "connecting to " + IoScheduler.PublicIdentityToString(destinationPublicIdentity)); return(false); } var myCertificateCollection = new X509CertificateCollection(); myCertificateCollection.Add(scheduler.MyCert); var myValidator = new CertificateValidator(scheduler, destinationPublicIdentity); try { stream = new SslStream(client.GetStream(), leaveInnerStreamOpen: false, myValidator.ValidateSSLCertificate); stream.AuthenticateAsClient(destinationPublicIdentity.FriendlyName, myCertificateCollection, checkCertificateRevocation: false); } catch (Exception e) { scheduler.ReportException(e, "authenticating connection to " + IoScheduler.PublicIdentityToString(destinationPublicIdentity)); return(false); } remoteCert = stream.RemoteCertificate as X509Certificate2; if (!ByteArrayComparer.Default().Equals(IoScheduler.GetCertificatePublicKey(remoteCert), destinationPublicKey)) { Console.Error.WriteLine("Connected to {0} expecting public key {1} but found public key {2}, so disconnecting.", IoScheduler.PublicIdentityToString(destinationPublicIdentity), IoScheduler.PublicKeyToString(destinationPublicKey), IoScheduler.PublicKeyToString(IoScheduler.GetCertificatePublicKey(remoteCert))); return(false); } if (scheduler.Verbose) { Console.WriteLine("Successfully connected to {0} and got certificate identifying it as {1}", IoScheduler.PublicIdentityToString(destinationPublicIdentity), IoScheduler.CertificateToString(remoteCert)); } // Now that the connection is successful, create a thread to // receive packets on it. ReceiverThread receiverThread = ReceiverThread.Create(scheduler, stream); return(true); }
public static string CertificateToString(X509Certificate2 cert) { return(string.Format("{0} (key {1})", cert.SubjectName.Name, PublicKeyToString(IoScheduler.GetCertificatePublicKey(cert)))); }
private ClientSenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKey) : base(i_scheduler, i_destinationPublicKey, null, null) { }
protected override string EndpointDescription() { return(IoScheduler.CertificateToString(remoteCert)); }
private ServerSenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKey, SslStream i_stream, X509Certificate2 i_remoteCert) : base(i_scheduler, i_destinationPublicKey, i_stream, i_remoteCert) { }
public CertificateValidator(IoScheduler i_scheduler, PublicIdentity i_expectedPublicIdentity = null) { scheduler = i_scheduler; expectedPublicIdentity = i_expectedPublicIdentity; }
public bool ValidateSSLCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { const SslPolicyErrors ignoredErrors = SslPolicyErrors.RemoteCertificateChainErrors; if ((sslPolicyErrors & ~ignoredErrors) != SslPolicyErrors.None) { Console.Error.WriteLine("Could not validate SSL certificate for {0} due to errors {1}", IoScheduler.GetCertificatePublicKey(certificate as X509Certificate2), sslPolicyErrors & ~ignoredErrors); return(false); } var cert2 = certificate as X509Certificate2; // If we were expecting a specific public identity, check that // the key in the certificate matches what we were expecting. if (expectedPublicIdentity != null) { if (!ByteArrayComparer.Default().Equals(IoScheduler.GetCertificatePublicKey(cert2), expectedPublicIdentity.PublicKey)) { Console.Error.WriteLine("Connected to {0} expecting public key {1} but found public key {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), IoScheduler.PublicKeyToString(expectedPublicIdentity.PublicKey), IoScheduler.PublicKeyToString(IoScheduler.GetCertificatePublicKey(cert2))); return(false); } if (cert2.SubjectName.Name != "CN=" + expectedPublicIdentity.FriendlyName) { Console.Error.WriteLine("Connected to {0} expecting subject CN={1} but found {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), expectedPublicIdentity.FriendlyName, cert2.SubjectName.Name); return(false); } } else { // If we weren't expecting any particular public identity, // consider the expected public identity to be the known one // matching the public key in the certificate we got. If // there is no known one, then this is just an anonymous // client, which is fine. Otherwise, check that the subject // matches what we expect. This is just a paranoid check; it // should never fail. expectedPublicIdentity = scheduler.LookupPublicKey(IoScheduler.GetCertificatePublicKey(cert2)); if (expectedPublicIdentity != null) { if (cert2.SubjectName.Name != "CN=" + expectedPublicIdentity.FriendlyName) { Console.Error.WriteLine("Received a certificate we expected to have subject CN={1} but found {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), expectedPublicIdentity.FriendlyName, cert2.SubjectName.Name); return(false); } } } return(true); }
private ReceiverThread(IoScheduler i_scheduler, SslStream i_stream) { scheduler = i_scheduler; stream = i_stream; remoteCert = stream.RemoteCertificate as X509Certificate2; }