internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult) { this.protocol.EndSendRecord(asyncResult); while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone) { this.SafeReceiveRecord(this.innerStream); if (this.context.AbbreviatedHandshake && this.context.LastHandshakeMsg == HandshakeType.ServerHello) { break; } } if (this.context.AbbreviatedHandshake) { ClientSessionCache.SetContextFromCache(this.context); this.context.Negotiating.Cipher.ComputeKeys(); this.context.Negotiating.Cipher.InitializeCipher(); this.protocol.SendChangeCipherSpec(); while (this.context.HandshakeState != HandshakeState.Finished) { this.SafeReceiveRecord(this.innerStream); } this.protocol.SendRecord(HandshakeType.Finished); } else { bool flag = this.context.ServerSettings.CertificateRequest; if (this.context.SecurityProtocol == SecurityProtocolType.Ssl3) { flag = (this.context.ClientSettings.Certificates != null && this.context.ClientSettings.Certificates.Count > 0); } if (flag) { this.protocol.SendRecord(HandshakeType.Certificate); } this.protocol.SendRecord(HandshakeType.ClientKeyExchange); this.context.Negotiating.Cipher.InitializeCipher(); if (flag && this.context.ClientSettings.ClientCertificate != null) { this.protocol.SendRecord(HandshakeType.CertificateVerify); } this.protocol.SendChangeCipherSpec(); this.protocol.SendRecord(HandshakeType.Finished); while (this.context.HandshakeState != HandshakeState.Finished) { this.SafeReceiveRecord(this.innerStream); } } this.context.HandshakeMessages.Reset(); this.context.ClearKeyInfo(); }
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 void OnNegotiateHandshakeCallback(IAsyncResult asyncResult) { this.protocol.EndSendRecord(asyncResult); // Read server response while (this.context.LastHandshakeMsg != HandshakeType.ServerHelloDone) { // Read next record SafeReceiveRecord(this.innerStream); // special case for abbreviated handshake where no ServerHelloDone is sent from the server if (this.context.AbbreviatedHandshake && (this.context.LastHandshakeMsg == HandshakeType.ServerHello)) { break; } } // the handshake is much easier if we can reuse a previous session settings if (this.context.AbbreviatedHandshake) { ClientSessionCache.SetContextFromCache(this.context); this.context.Negotiating.Cipher.ComputeKeys(); this.context.Negotiating.Cipher.InitializeCipher(); // Send Cipher Spec protocol this.protocol.SendChangeCipherSpec(); // Read record until server finished is received while (this.context.HandshakeState != HandshakeState.Finished) { // If all goes well this will process messages: // Change Cipher Spec // Server finished SafeReceiveRecord(this.innerStream); } // Send Finished message this.protocol.SendRecord(HandshakeType.Finished); } else { // Send client certificate if requested // even if the server ask for it it _may_ still be optional bool clientCertificate = this.context.ServerSettings.CertificateRequest; // 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) } if (clientCertificate) { this.protocol.SendRecord(HandshakeType.Certificate); } // Send Client Key Exchange this.protocol.SendRecord(HandshakeType.ClientKeyExchange); // 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)) { this.protocol.SendRecord(HandshakeType.CertificateVerify); } // Send Cipher Spec protocol this.protocol.SendChangeCipherSpec(); // Send Finished message this.protocol.SendRecord(HandshakeType.Finished); // Read record until server finished is received while (this.context.HandshakeState != HandshakeState.Finished) { // If all goes well this will process messages: // Change Cipher Spec // Server finished SafeReceiveRecord(this.innerStream); } } // Reset Handshake messages information this.context.HandshakeMessages.Reset(); // Clear Key Info this.context.ClearKeyInfo(); }