+2004-03-17 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls.Handshake.Server/TlsClientCertificate.cs:\r
+ * Mono.Security.Protocol.Tls.Handshake.Server/TlsServerKeyExchange.cs:\r
+\r
+ - Initial implementation.\r
+\r
+\r
+2004-03-16 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/SslCipherSuite.cs:\r
+\r
+ - Added changes for allow it to work as server or client.\r
+\r
+\r
+2004-03-15 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/TlsStream.cs:\r
+ * Mono.Security.Protocol.Tls/CipherSuite.cs:\r
+ * Mono.Security.Protocol.Tls/TlsCipherSuite.cs:\r
+ * Mono.Security.Protocol.Tls/SslHandshakeHash.cs:\r
+ * Mono.Security.Protocol.Tls/RecordProtocol.cs:\r
+ * Mono.Security.Cryptography/MD5SHA1.cs:\r
+\r
+ - Use Buffer.BlockCopy instead of System.Array.Copy
+
2004-03-10 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
\r
* Mono.Security.Protocol.Tls.Handshake.Client/TlsClientCertificateVerify.cs:\r
byte[] hash = new byte[36];
- System.Array.Copy(this.md5.Hash, 0, hash, 0, 16);
- System.Array.Copy(this.sha.Hash, 0, hash, 16, 20);
+ Buffer.BlockCopy(this.md5.Hash, 0, hash, 0, 16);
+ Buffer.BlockCopy(this.sha.Hash, 0, hash, 16, 20);
return hash;
}
*/
if (this.ReadInt16() != 0)
{
- ASN1 rdn = new ASN1(this.ReadBytes(this.ReadInt16()));
+ ASN1 rdn = new ASN1(this.ReadBytes(this.ReadInt16()));
distinguisedNames = new string[rdn.Count];
- #warning "needs testing"
for (int i = 0; i < rdn.Count; i++)
{
// element[0] = attributeType
{
internal class TlsClientCertificate : HandshakeMessage
{
+ #region Fields
+
+ private X509Certificate clientCertificate;
+
+ #endregion
+
#region Constructors
public TlsClientCertificate(Context context, byte[] buffer)
public override void Update()
{
- throw new NotSupportedException();
+ this.Context.ClientSettings.Certificates.Add(clientCertificate);
}
#endregion
protected override void ProcessAsTls1()
{
- throw new NotSupportedException();
+ int length = this.ReadInt24();
+ this.clientCertificate = new X509Certificate(this.ReadBytes(length));
+
+#warning "Is client certificate validation needed ??"
}
#endregion
protected override void ProcessAsSsl3()
{
+ bool decryptError = false;
+
// Compute handshake messages hashes
HashAlgorithm hash = new SslHandshakeHash(this.Context.MasterSecret);
// Check client prf against server prf
if (clientHash.Length != serverHash.Length)
{
- throw new TlsException("Invalid ServerFinished message received.");
+ decryptError = true;
}
-
- for (int i = 0; i < clientHash.Length; i++)
+ else
{
- if (clientHash[i] != serverHash[i])
+ for (int i = 0; i < clientHash.Length; i++)
{
- throw new TlsException("Invalid ServerFinished message received.");
+ if (clientHash[i] != serverHash[i])
+ {
+ decryptError = true;
+ break;
+ }
}
}
+
+ if (decryptError)
+ {
+ this.Context.RecordProtocol.SendAlert(AlertDescription.DecryptError);
+
+ throw new TlsException("Decrypt error.");
+ }
}
protected override void ProcessAsTls1()
{
- byte[] clientPRF = this.ReadBytes((int)this.Length);
- HashAlgorithm hash = new MD5SHA1();
+ byte[] clientPRF = this.ReadBytes((int)this.Length);
+ HashAlgorithm hash = new MD5SHA1();
+ bool decryptError = false;
hash.ComputeHash(
this.Context.HandshakeMessages.ToArray(),
// Check client prf against server prf
if (clientPRF.Length != serverPRF.Length)
{
- throw new TlsException("Invalid ServerFinished message received.");
+ decryptError = true;
}
-
- for (int i = 0; i < serverPRF.Length; i++)
+ else
{
- if (clientPRF[i] != serverPRF[i])
+ for (int i = 0; i < serverPRF.Length; i++)
{
- throw new TlsException("Invalid ServerFinished message received.");
+ if (clientPRF[i] != serverPRF[i])
+ {
+ decryptError = true;
+ }
}
}
+
+ if (decryptError)
+ {
+ this.Context.RecordProtocol.SendAlert(AlertDescription.DecryptError);
+
+ throw new TlsException("Decrypt error.");
+ }
}
#endregion
}
else
{
-#warning "Send alert"
+ this.Context.RecordProtocol.SendAlert(AlertDescription.ProtocolVersion);
+
throw this.Context.CreateException("Incorrect protocol version received from server");
}
}
private void selectCipherSuite()
{
int index = 0;
+
for (int i = 0; i < this.cipherSuites.Length; i++)
{
if ((index = this.Context.SupportedCiphers.IndexOf(this.cipherSuites[i])) != -1)
if (this.Context.Cipher == null)
{
-#warning "Send an Alert and Throw and exception"
+ this.Context.RecordProtocol.SendAlert(AlertDescription.InsuficientSecurity);
+
+ throw this.Context.CreateException("Insuficient Security");
}
}
using System;
using System.Security.Cryptography;
+using SX509 = System.Security.Cryptography.X509Certificates;
+
using Mono.Security.Cryptography;
using Mono.Security.X509;
protected override void ProcessAsTls1()
{
- throw new NotSupportedException();
+ ServerContext context = (ServerContext)this.Context;
+
+ // Select the private key information
+ RSA rsa = (RSA)context.SslStream.PrivateKeyCertSelectionDelegate(
+ new SX509.X509Certificate(context.ServerSettings.Certificates[0].RawData),
+ null);
+
+ RSAParameters rsaParams = rsa.ExportParameters(false);
+
+ // Write Modulus
+ this.WriteInt24(rsaParams.Modulus.Length);
+ this.Write(rsaParams.Modulus, 0, rsaParams.Modulus.Length);
+
+ // Write exponent
+ this.WriteInt24(rsaParams.Exponent.Length);
+ this.Write(rsaParams.Exponent, 0, rsaParams.Exponent.Length);
+
+ // Write signed params
+ byte[] signature = this.createSignature(rsa, this.ToArray());
+ this.WriteInt24(signature.Length);
+ this.Write(signature);
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private byte[] createSignature(RSA rsa, byte[] buffer)
+ {
+ MD5SHA1 hash = new MD5SHA1();
+
+ // Create server params array
+ TlsStream stream = new TlsStream();
+
+ stream.Write(this.Context.RandomCS);
+ stream.Write(buffer, 0, buffer.Length);
+
+ hash.ComputeHash(stream.ToArray());
+
+ stream.Reset();
+
+ return hash.CreateSignature(rsa);
}
#endregion
+2004-03-16 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/SslCipherSuite.cs:\r
+\r
+ - Added changes for allow it to work as server or client.\r
+\r
+2004-03-15 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
+\r
+ * Mono.Security.Protocol.Tls/TlsStream.cs:\r
+ * Mono.Security.Protocol.Tls/CipherSuite.cs:\r
+ * Mono.Security.Protocol.Tls/TlsCipherSuite.cs:\r
+ * Mono.Security.Protocol.Tls/SslHandshakeHash.cs:\r
+ * Mono.Security.Protocol.Tls/RecordProtocol.cs:\r
+\r
+ - Use Buffer.BlockCopy instead of System.Array.Copy
+
2004-03-10 Carlos Guzman Alvarez <carlosga@telefonica.net>\r
\r
* Mono.Security.Protocol.Tls/Ciphersuite.cs:\r
// Secret 1
byte[] secret1 = new byte[secretLen];
- System.Array.Copy(secret, 0, secret1, 0, secretLen);
+ Buffer.BlockCopy(secret, 0, secret1, 0, secretLen);
// Secret2
byte[] secret2 = new byte[secretLen];
- System.Array.Copy(secret, secretLen, secret2, 0, secretLen);
+ Buffer.BlockCopy(secret, secretLen, secret2, 0, secretLen);
// Secret 1 processing
byte[] p_md5 = Expand("MD5", secret1, seed, length);
byte[] res = new byte[length];
- System.Array.Copy(resMacs.ToArray(), 0, res, 0, res.Length);
+ Buffer.BlockCopy(resMacs.ToArray(), 0, res, 0, res.Length);
resMacs.Reset();
// Secure Random generator
private RandomNumberGenerator random;
+ // Record protocol
+ private RecordProtocol recordProtocol;
+
#endregion
#region Properties
set { this.serverWriteIV = value; }
}
+ public RecordProtocol RecordProtocol
+ {
+ get { return this.recordProtocol; }
+ set { this.recordProtocol = value; }
+ }
+
#endregion
#region Constructors
public RecordProtocol(Stream innerStream, Context context)
{
- this.innerStream = innerStream;
- this.context = context;
+ this.innerStream = innerStream;
+ this.context = context;
+ this.context.RecordProtocol = this;
}
#endregion
if (this.context.Cipher.CipherMode == CipherMode.CBC)
{
byte[] iv = new byte[this.context.Cipher.IvSize];
- System.Array.Copy(ecr, ecr.Length - iv.Length, iv, 0, iv.Length);
+ Buffer.BlockCopy(ecr, ecr.Length - iv.Length, iv, 0, iv.Length);
this.context.Cipher.UpdateClientCipherIV(iv);
}
ContentType contentType,
byte[] fragment)
{
- byte[] dcrFragment = null;
- byte[] dcrMAC = null;
+ byte[] dcrFragment = null;
+ byte[] dcrMAC = null;
+ bool badRecordMac = false;
- // Decrypt message
- this.context.Cipher.DecryptRecord(fragment, ref dcrFragment, ref dcrMAC);
+ try
+ {
+ this.context.Cipher.DecryptRecord(fragment, ref dcrFragment, ref dcrMAC);
+ }
+ catch
+ {
+ if (this.context is ServerContext)
+ {
+ this.Context.RecordProtocol.SendAlert(AlertDescription.DecryptionFailed);
+ }
+
+ throw;
+ }
- // Check MAC code
+ // Generate record MAC
byte[] mac = null;
+
if (this.Context is ClientContext)
{
mac = this.context.Cipher.ComputeServerRecordMAC(contentType, dcrFragment);
mac = this.context.Cipher.ComputeClientRecordMAC(contentType, dcrFragment);
}
- // Check that the mac is correct
+ // Check record MAC
if (mac.Length != dcrMAC.Length)
{
- throw new TlsException("Invalid MAC received from server.");
+ badRecordMac = true;
+ }
+ else
+ {
+ for (int i = 0; i < mac.Length; i++)
+ {
+ if (mac[i] != dcrMAC[i])
+ {
+ badRecordMac = true;
+ break;
+ }
+ }
}
- for (int i = 0; i < mac.Length; i++)
+ if (badRecordMac)
{
- if (mac[i] != dcrMAC[i])
+ if (this.context is ServerContext)
{
- throw new TlsException("Invalid MAC received from server.");
+ this.Context.RecordProtocol.SendAlert(AlertDescription.BadRecordMAC);
}
+
+ throw new TlsException("Bad record MAC");
}
// Update sequence number
block.Write(this.Context.ServerWriteMAC);
block.Write(this.pad1);
- block.Write(this.Context.ReadSequenceNumber);
+ if (this.Context is ClientContext)
+ {
+ block.Write(this.Context.ReadSequenceNumber);
+ }
+ else
+ {
+ block.Write(this.Context.WriteSequenceNumber);
+ }
block.Write((byte)contentType);
block.Write((short)fragment.Length);
block.Write(fragment);
block.Write(this.Context.ClientWriteMAC);
block.Write(this.pad1);
- block.Write(this.Context.WriteSequenceNumber);
+ if (this.Context is ClientContext)
+ {
+ block.Write(this.Context.ReadSequenceNumber);
+ }
+ else
+ {
+ block.Write(this.Context.WriteSequenceNumber);
+ }
block.Write((byte)contentType);
block.Write((short)fragment.Length);
block.Write(fragment);
byte[] result = new byte[36];
- System.Array.Copy(md5.Hash, 0, result, 0, 16);
- System.Array.Copy(sha.Hash, 0, result, 16, 20);
+ Buffer.BlockCopy(md5.Hash, 0, result, 0, 16);
+ Buffer.BlockCopy(sha.Hash, 0, result, 16, 20);
return result;
}
if (this.context.Cipher.ExchangeAlgorithmType == ExchangeAlgorithmType.RsaKeyX)
{
this.protocol.SendRecord(HandshakeType.ServerKeyExchange);
-
}
// If the negotiated cipher is a KeyEx cipher or
// Generate IV keys
this.Context.ClientWriteIV = new byte[this.IvSize];
- System.Array.Copy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length);
+ Buffer.BlockCopy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length);
this.Context.ServerWriteIV = new byte[this.IvSize];
- System.Array.Copy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length);
+ Buffer.BlockCopy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length);
}
// Clear no more needed data
int int24 = IPAddress.HostToNetworkOrder(value);
byte[] content = new byte[3];
- System.Array.Copy(BitConverter.GetBytes(int24), 1, content, 0, 3);
+ Buffer.BlockCopy(BitConverter.GetBytes(int24), 1, content, 0, 3);
Write(content);
}