internal override void EndNegotiateHandshake(IAsyncResult result) { NegotiateAsyncResult negotiate = result as NegotiateAsyncResult; if (negotiate == null) { throw new ArgumentNullException(); } if (!negotiate.IsCompleted) { negotiate.AsyncWaitHandle.WaitOne(); } if (negotiate.CompletedWithError) { throw negotiate.AsyncException; } }
internal override IAsyncResult BeginNegotiateHandshake(AsyncCallback callback, object state) { if (this.context.HandshakeState != HandshakeState.None) { this.context.Clear(); } // Obtain supported cipher suites this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(false, context.SecurityProtocol); // Set handshake state this.context.HandshakeState = HandshakeState.Started; NegotiateAsyncResult result = new NegotiateAsyncResult(callback, state, NegotiateState.SentClientHello); // Begin sending the client hello this.protocol.BeginSendRecord(HandshakeType.ClientHello, NegotiateAsyncWorker, result); return(result); }
private void NegotiateAsyncWorker(IAsyncResult result) { NegotiateAsyncResult negotiate = result.AsyncState as NegotiateAsyncResult; try { switch (negotiate.State) { case NegotiateState.SentClientHello: this.protocol.EndSendRecord(result); // we are now ready to ready the receive the hello response. negotiate.State = NegotiateState.ReceiveClientHelloResponse; // Start reading the client hello response this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); break; case NegotiateState.ReceiveClientHelloResponse: this.SafeEndReceiveRecord(result, true); if (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone && (!this.context.AbbreviatedHandshake || this.context.LastHandshakeMsg != HandshakeType.ServerHello)) { // Read next record (skip empty, e.g. warnings alerts) this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); break; } // special case for abbreviated handshake where no ServerHelloDone is sent from the server if (this.context.AbbreviatedHandshake) { ClientSessionCache.SetContextFromCache(this.context); this.context.Negotiating.Cipher.ComputeKeys(); this.context.Negotiating.Cipher.InitializeCipher(); negotiate.State = NegotiateState.SentCipherSpec; // Send Change Cipher Spec message with the current cipher // or as plain text if this is the initial negotiation this.protocol.BeginSendChangeCipherSpec(NegotiateAsyncWorker, negotiate); } else { // Send client certificate if requested // even if the server ask for it it _may_ still be optional bool clientCertificate = this.context.ServerSettings.CertificateRequest; using (var memstream = new MemoryStream()) { // NOTE: sadly SSL3 and TLS1 differs in how they handle this and // the current design doesn't allow a very cute way to handle // SSL3 alert warning for NoCertificate (41). if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3) { clientCertificate = ((this.context.ClientSettings.Certificates != null) && (this.context.ClientSettings.Certificates.Count > 0)); // this works well with OpenSSL (but only for SSL3) } byte[] record = null; if (clientCertificate) { record = this.protocol.EncodeHandshakeRecord(HandshakeType.Certificate); memstream.Write(record, 0, record.Length); } // Send Client Key Exchange record = this.protocol.EncodeHandshakeRecord(HandshakeType.ClientKeyExchange); memstream.Write(record, 0, record.Length); // Now initialize session cipher with the generated keys this.context.Negotiating.Cipher.InitializeCipher(); // Send certificate verify if requested (optional) if (clientCertificate && (this.context.ClientSettings.ClientCertificate != null)) { record = this.protocol.EncodeHandshakeRecord(HandshakeType.CertificateVerify); memstream.Write(record, 0, record.Length); } // send the chnage cipher spec. this.protocol.SendChangeCipherSpec(memstream); // Send Finished message record = this.protocol.EncodeHandshakeRecord(HandshakeType.Finished); memstream.Write(record, 0, record.Length); negotiate.State = NegotiateState.SentKeyExchange; // send all the records. this.innerStream.BeginWrite(memstream.GetBuffer(), 0, (int)memstream.Length, NegotiateAsyncWorker, negotiate); } } break; case NegotiateState.SentKeyExchange: this.innerStream.EndWrite(result); negotiate.State = NegotiateState.ReceiveFinishResponse; this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); break; case NegotiateState.ReceiveFinishResponse: this.SafeEndReceiveRecord(result); // Read record until server finished is received if (this.context.HandshakeState != HandshakeState.Finished) { // If all goes well this will process messages: // Change Cipher Spec // Server finished this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); } else { // Reset Handshake messages information this.context.HandshakeMessages.Reset(); // Clear Key Info this.context.ClearKeyInfo(); negotiate.SetComplete(); } break; case NegotiateState.SentCipherSpec: this.protocol.EndSendChangeCipherSpec(result); negotiate.State = NegotiateState.ReceiveCipherSpecResponse; // Start reading the cipher spec response this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); break; case NegotiateState.ReceiveCipherSpecResponse: this.SafeEndReceiveRecord(result, true); if (this.context.HandshakeState != HandshakeState.Finished) { this.protocol.BeginReceiveRecord(this.innerStream, NegotiateAsyncWorker, negotiate); } else { negotiate.State = NegotiateState.SentFinished; this.protocol.BeginSendRecord(HandshakeType.Finished, NegotiateAsyncWorker, negotiate); } break; case NegotiateState.SentFinished: this.protocol.EndSendRecord(result); // Reset Handshake messages information this.context.HandshakeMessages.Reset(); // Clear Key Info this.context.ClearKeyInfo(); negotiate.SetComplete(); break; } } catch (TlsException ex) { try { Exception e = ex; this.protocol.SendAlert(ref e); } catch { } negotiate.SetComplete(new IOException("The authentication or decryption has failed.", ex)); } catch (Exception ex) { try { this.protocol.SendAlert(AlertDescription.InternalError); } catch { } negotiate.SetComplete(new IOException("The authentication or decryption has failed.", ex)); } }
internal override IAsyncResult BeginNegotiateHandshake(AsyncCallback callback, object state) { if (this.context.HandshakeState != HandshakeState.None) { this.context.Clear (); } // Obtain supported cipher suites this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers (false, context.SecurityProtocol); // Set handshake state this.context.HandshakeState = HandshakeState.Started; NegotiateAsyncResult result = new NegotiateAsyncResult (callback, state, NegotiateState.SentClientHello); // Begin sending the client hello this.protocol.BeginSendRecord (HandshakeType.ClientHello, NegotiateAsyncWorker, result); return result; }