+2004-02-26 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/HandshakeState.cs:\r
+\r
+ - New file.\r
+\r
+ * Mono.Security.Protocol.Tls.Alerts/TlsAlert.cs:\r
+\r
+ - Modified the level of some alerts according to the RFC.\r
+\r
+ * Mono.Security.Protocol.Tls/SslClientStream.cs:\r
+ * Mono.Security.Protocol.Tls/SslServerStream.cs:\r
+ * Mono.Security.Protocol.Tls/Context.cs:\r
+ * Mono.Security.Protocol.Tls/ClientContext.cs:\r
+ * Mono.Security.Protocol.Tls/ClientRecordProtocol.cs:\r
+ * Mono.Security.Protocol.Tls.Handshake.Client/TlsServerFinished.cs:\r
+\r
+ - Added changes for better handling of ClientHelloRequest messages.
+
2004-02-25 Sebastien Pouliot <sebastien@ximian.com>
* Mono.Security.dll.sources: Added new internal class HttpsClientStream
switch (description)
{
case TlsAlertDescription.CloseNotify:
+ case TlsAlertDescription.NoRenegotiation:
+ case TlsAlertDescription.UserCancelled:
this.level = TlsAlertLevel.Warning;
break;
case TlsAlertDescription.IlegalParameter:
case TlsAlertDescription.InsuficientSecurity:
case TlsAlertDescription.InternalError:
- case TlsAlertDescription.NoRenegotiation:
case TlsAlertDescription.ProtocolVersion:
case TlsAlertDescription.RecordOverflow:
case TlsAlertDescription.UnexpectedMessage:
case TlsAlertDescription.UnknownCA:
case TlsAlertDescription.UnsupportedCertificate:
- case TlsAlertDescription.UserCancelled:
default:
this.level = TlsAlertLevel.Fatal;
break;
+2004-02-26 Carlos Guzman Alvarez <carlosga@telefonica.net>
+\r
+ * Mono.Security.Protocol.Tls.Handshake.Client/TlsServerFinished.cs:\r
+\r
+ - Added changes for better handling of ClientHelloRequest messages.
+
2004-02-21 Carlos Guzman Alvarez <carlosga@telefonica.net>
* TlsServerHello: Fix for handle SecurityProtocolType.Default.
this.Context.HandshakeMessages.Reset();
// Hahdshake is finished
- this.Context.HandshakeFinished = true;
+ this.Context.HandshakeState = HandshakeState.Finished;
}
#endregion
+2004-02-26 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/HandshakeState.cs:\r
+\r
+ - New file.\r
+\r
+ * Mono.Security.Protocol.Tls/SslClientStream.cs:\r
+ * Mono.Security.Protocol.Tls/SslServerStream.cs:\r
+ * Mono.Security.Protocol.Tls/Context.cs:\r
+ * Mono.Security.Protocol.Tls/ClientContext.cs:\r
+ * Mono.Security.Protocol.Tls/ClientRecordProtocol.cs:\r
+\r
+ - Added changes for better handling of ClientHelloRequest messages.
+
2004-02-25 Sebastien Pouliot <sebastien@ximian.com>
* HttpsClientStream.cs: New. Internal glue class between System.dll
}
#endregion
+
+ #region Methods
+
+ public override void Clear()
+ {
+ this.helloDone = false;
+ this.clientHelloProtocol = 0;
+
+ base.Clear();
+ }
+
+ #endregion
}
}
private TlsHandshakeMessage createServerHandshakeMessage(
TlsHandshakeType type, byte[] buffer)
{
+ ClientContext context = (ClientContext)this.context;
+
switch (type)
{
case TlsHandshakeType.HelloRequest:
- this.SendRecord(TlsHandshakeType.ClientHello);
+ if (context.HandshakeState != HandshakeState.Started)
+ {
+ context.SslStream.NegotiateHandshake();
+ }
+ else
+ {
+ this.SendAlert(
+ TlsAlertLevel.Warning,
+ TlsAlertDescription.NoRenegotiation);
+ }
return null;
case TlsHandshakeType.ServerHello:
private CipherSuite cipher;
private TlsCipherSuiteCollection supportedCiphers;
+ // Handshake negotiation state
+ private HandshakeState handshakeState;
+
// Misc
private bool isActual;
- private bool handshakeFinished;
private bool connectionEnd;
private bool protocolNegotiated;
set { this.isActual = value; }
}
- public bool HandshakeFinished
+ public HandshakeState HandshakeState
{
- get { return handshakeFinished; }
- set { handshakeFinished = value; }
+ get { return this.handshakeState; }
+ set { this.handshakeState = value; }
}
public bool ConnectionEnd
this.clientSettings = new TlsClientSettings();
this.handshakeMessages = new TlsStream();
this.sessionId = null;
+ this.handshakeState = HandshakeState.None;
this.random = RandomNumberGenerator.Create();
}
return secureBytes;
}
- public void ClearKeyInfo()
+ public virtual void Clear()
+ {
+ this.compressionMethod = SecurityCompressionType.None;
+ this.serverSettings = new TlsServerSettings();
+ this.clientSettings = new TlsClientSettings();
+ this.handshakeMessages = new TlsStream();
+ this.sessionId = null;
+ this.handshakeState = HandshakeState.None;
+
+ this.ClearKeyInfo();
+ }
+
+ public virtual void ClearKeyInfo()
{
// Clear Master Secret
this.masterSecret = null;
this.serverWriteKey = null;
this.serverWriteIV = null;
+ // Reset handshake messages
+ this.handshakeMessages.Reset();
+
// Clear MAC keys if protocol is different than Ssl3
if (this.securityProtocol != SecurityProtocolType.Ssl3)
{
--- /dev/null
+/* Transport Security Layer (TLS)
+ * Copyright (c) 2003-2004 Carlos Guzman Alvarez
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+using System;
+
+namespace Mono.Security.Protocol.Tls
+{
+ [Serializable]
+ internal enum HandshakeState
+ {
+ None,
+ Started,
+ Finished
+ }
+}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.CipherAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.EffectiveKeyBits;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.HashAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.HashSize * 8;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.ServerSettings.Certificates[0].RSA.KeySize;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.ExchangeAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.SecurityProtocol;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
if (this.context.ServerSettings.Certificates != null &&
this.context.ServerSettings.Certificates.Count > 0)
{
if (this.innerStream != null)
{
- if (this.context.HandshakeFinished &&
+ if (this.context.HandshakeState == HandshakeState.Finished &&
!this.context.ConnectionEnd)
{
// Write close notify
lock (this)
{
- if (!this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.None)
{
- this.doHandshake(); // Handshake negotiation
+ this.NegotiateHandshake();
}
}
- /*
- if (!Monitor.TryEnter(this.read))
- {
- throw new InvalidOperationException("A read operation is already in progress.");
- }
- System.Threading.Monitor.Enter(this.read);
- */
-
IAsyncResult asyncResult;
lock (this.read)
throw new IOException("IO exception during read.");
}
}
- /*
- finally
- {
- Monitor.Exit(this.read);
- }
- */
return asyncResult;
}
lock (this)
{
- if (!this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.None)
{
- // Start handshake negotiation
- this.doHandshake();
+ this.NegotiateHandshake();
}
}
- /*
- if (!Monitor.TryEnter(this.write))
- {
- throw new InvalidOperationException("A write operation is already in progress.");
- }
- Monitor.Enter(this.write);
- */
-
IAsyncResult asyncResult;
lock (this.write)
}
}
- /*
- finally
- {
- Monitor.Exit(this.write);
- }
- */
-
return asyncResult;
}
Fig. 1 - Message flow for a full handshake
*/
- private void doHandshake()
+ internal void NegotiateHandshake()
{
- try
+ lock (this)
{
- // Obtain supported cipher suites
- this.context.SupportedCiphers = TlsCipherSuiteFactory.GetSupportedCiphers(this.context.SecurityProtocol);
+ try
+ {
+ if (this.context.HandshakeState != HandshakeState.None)
+ {
+ this.context.Clear();
+ }
- // Send client hello
- this.protocol.SendRecord(TlsHandshakeType.ClientHello);
+ // Obtain supported cipher suites
+ this.context.SupportedCiphers = TlsCipherSuiteFactory.GetSupportedCiphers(this.context.SecurityProtocol);
- // Read server response
- while (!this.context.HelloDone)
- {
- // Read next record
- this.protocol.ReceiveRecord();
- }
+ // Send client hello
+ this.protocol.SendRecord(TlsHandshakeType.ClientHello);
- // Send client certificate if requested
- if (this.context.ServerSettings.CertificateRequest)
- {
- this.protocol.SendRecord(TlsHandshakeType.Certificate);
- }
+ // Read server response
+ while (!this.context.HelloDone)
+ {
+ // Read next record
+ this.protocol.ReceiveRecord();
+ }
- // Send Client Key Exchange
- this.protocol.SendRecord(TlsHandshakeType.ClientKeyExchange);
+ // Send client certificate if requested
+ if (this.context.ServerSettings.CertificateRequest)
+ {
+ this.protocol.SendRecord(TlsHandshakeType.Certificate);
+ }
- // Now initialize session cipher with the generated keys
- this.context.Cipher.InitializeCipher();
+ // Send Client Key Exchange
+ this.protocol.SendRecord(TlsHandshakeType.ClientKeyExchange);
- // Send certificate verify if requested
- if (this.context.ServerSettings.CertificateRequest)
- {
- this.protocol.SendRecord(TlsHandshakeType.CertificateVerify);
- }
+ // Now initialize session cipher with the generated keys
+ this.context.Cipher.InitializeCipher();
+
+ // Send certificate verify if requested
+ if (this.context.ServerSettings.CertificateRequest)
+ {
+ this.protocol.SendRecord(TlsHandshakeType.CertificateVerify);
+ }
- // Send Cipher Spec protocol
- this.protocol.SendChangeCipherSpec();
+ // Send Cipher Spec protocol
+ this.protocol.SendChangeCipherSpec();
- // Read record until server finished is received
- while (!this.context.HandshakeFinished)
+ // 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
+ this.protocol.ReceiveRecord();
+ }
+
+ // Clear Key Info
+ this.context.ClearKeyInfo();
+ }
+ catch
{
- // If all goes well this will process messages:
- // Change Cipher Spec
- // Server finished
- this.protocol.ReceiveRecord();
+ throw new IOException("The authentication or decryption has failed.");
}
-
- // Clear Key Info
- this.context.ClearKeyInfo();
- }
- catch
- {
- throw new IOException("The authentication or decryption has failed.");
}
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.CipherAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.EffectiveKeyBits;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.ClientSettings.ClientCertificate;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.HashAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.HashSize * 8;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.ServerSettings.Certificates[0].RSA.KeySize;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.Cipher.ExchangeAlgorithmType;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
return this.context.SecurityProtocol;
}
{
get
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
if (this.context.ServerSettings.Certificates != null &&
this.context.ServerSettings.Certificates.Count > 0)
{
if (this.innerStream != null)
{
- if (this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.Finished)
{
// Write close notify
this.protocol.SendAlert(TlsAlertDescription.CloseNotify);
lock (this)
{
- if (!this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.None)
{
this.doHandshake(); // Handshake negotiation
}
lock (this)
{
- if (!this.context.HandshakeFinished)
+ if (this.context.HandshakeState == HandshakeState.None)
{
// Start handshake negotiation
this.doHandshake();