+// Transport Security Layer (TLS)
+// Copyright (c) 2003-2004 Carlos Guzman Alvarez
//
// Permission is hereby granted, free of charge, to any person obtaining
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-/* 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;
{
CipherSuiteCollection scs = new CipherSuiteCollection(SecurityProtocolType.Ssl3);
- // Supported ciphers
- scs.Add((0x00 << 0x08) | 0x0A, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", CipherAlgorithmType.TripleDes, HashAlgorithmType.Sha1, ExchangeAlgorithmType.RsaSign, false, true, 24, 24, 168, 8, 8);
+ // Supported ciphers\r
+ scs.Add((0x00 << 0x08) | 0x35, "SSL_RSA_WITH_AES_256_CBC_SHA", CipherAlgorithmType.Rijndael, HashAlgorithmType.Sha1, ExchangeAlgorithmType.RsaSign, false, true, 32, 32, 256, 16, 16);\r
+ scs.Add((0x00 << 0x08) | 0x0A, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", CipherAlgorithmType.TripleDes, HashAlgorithmType.Sha1, ExchangeAlgorithmType.RsaSign, false, true, 24, 24, 168, 8, 8);\r
scs.Add((0x00 << 0x08) | 0x05, "SSL_RSA_WITH_RC4_128_SHA", CipherAlgorithmType.Rc4, HashAlgorithmType.Sha1, ExchangeAlgorithmType.RsaSign, false, false, 16, 16, 128, 0, 0);
scs.Add((0x00 << 0x08) | 0x04, "SSL_RSA_WITH_RC4_128_MD5", CipherAlgorithmType.Rc4, HashAlgorithmType.Md5, ExchangeAlgorithmType.RsaSign, false, false, 16, 16, 128, 0, 0);
scs.Add((0x00 << 0x08) | 0x09, "SSL_RSA_WITH_DES_CBC_SHA", CipherAlgorithmType.Des, HashAlgorithmType.Sha1, ExchangeAlgorithmType.RsaSign, false, true, 8, 8, 56, 8, 8);
+// Transport Security Layer (TLS)
+// Copyright (c) 2003-2004 Carlos Guzman Alvarez
//
// Permission is hereby granted, free of charge, to any person obtaining
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-/* 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;
using System.Text;
}
}
+ public void ChangeProtocol(short protocol)
+ {
+ SecurityProtocolType protocolType = this.DecodeProtocolCode(protocol);
+
+ if ((protocolType & this.SecurityProtocolFlags) == protocolType ||
+ (this.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
+ {
+ this.SecurityProtocol = protocolType;
+ this.SupportedCiphers.Clear();
+ this.SupportedCiphers = null;
+ this.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers(protocolType);
+ }
+ else
+ {
+ throw new TlsException(AlertDescription.ProtocolVersion, "Incorrect protocol version received from server");
+ }
+ }
+
#endregion
}
}
+// Transport Security Layer (TLS)
+// Copyright (c) 2003-2004 Carlos Guzman Alvarez
//
// Permission is hereby granted, free of charge, to any person obtaining
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-/* 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;
+using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
AlertDescription.InternalError,
"The session is finished and it's no longer valid.");
}
-
+
// Try to read the Record Content Type
int type = this.innerStream.ReadByte();
-
- // There are no more data for read
if (type == -1)
{
return null;
}
ContentType contentType = (ContentType)type;
- short protocol = this.readShort();
- short length = this.readShort();
-
- // Read Record data
- int received = 0;
- byte[] buffer = new byte[length];
- while (received != length)
- {
- received += this.innerStream.Read(
- buffer, received, buffer.Length - received);
- }
-
- DebugHelper.WriteLine(
- ">>>> Read record ({0}|{1})",
- this.context.DecodeProtocolCode(protocol),
- contentType);
- DebugHelper.WriteLine("Record data", buffer);
+ byte[] buffer = this.ReadRecordBuffer(type);
TlsStream message = new TlsStream(buffer);
- // Check that the message has a valid protocol version
- if (protocol != this.context.Protocol &&
- this.context.ProtocolNegotiated)
- {
- throw new TlsException(
- AlertDescription.ProtocolVersion,
- "Invalid protocol version on message received from server");
- }
-
// Decrypt message contents if needed
- if (contentType == ContentType.Alert && length == 2)
+ if (contentType == ContentType.Alert && buffer.Length == 2)
{
}
else
{
- if (this.context.IsActual &&
- contentType != ContentType.ChangeCipherSpec)
+ if (this.context.IsActual && contentType != ContentType.ChangeCipherSpec)
{
- message = this.decryptRecordFragment(
- contentType,
- message.ToArray());
+ message = this.decryptRecordFragment(contentType, message.ToArray());
DebugHelper.WriteLine("Decrypted record data", message.ToArray());
}
switch (contentType)
{
case ContentType.Alert:
- this.processAlert(
- (AlertLevel)message.ReadByte(),
- (AlertDescription)message.ReadByte());
+ this.ProcessAlert((AlertLevel)message.ReadByte(), (AlertDescription)message.ReadByte());
+ result = null;
break;
case ContentType.ChangeCipherSpec:
this.context.HandshakeMessages.Write(message.ToArray());
break;
+// FIXME / MCS bug - http://bugzilla.ximian.com/show_bug.cgi?id=67711
+// case (ContentType)0x80:
+// this.context.HandshakeMessages.Write (result);
+// break;
+
default:
- throw new TlsException(
- AlertDescription.UnexpectedMessage,
- "Unknown record received from server.");
+ if (contentType != (ContentType)0x80)
+ {
+ throw new TlsException(
+ AlertDescription.UnexpectedMessage,
+ "Unknown record received from server.");
+ }
+ this.context.HandshakeMessages.Write (result);
+ break;
}
return result;
}
- private short readShort()
+ private byte[] ReadRecordBuffer(int contentType)
+ {
+ switch (contentType)
+ {
+ case 0x80:
+ return this.ReadClientHelloV2();
+
+ default:
+ if (!Enum.IsDefined(typeof(ContentType), (ContentType)contentType))
+ {
+ throw new TlsException(AlertDescription.DecodeError);
+ }
+ return this.ReadStandardRecordBuffer();
+ }
+ }
+
+ private byte[] ReadClientHelloV2()
+ {
+ int msgLength = this.innerStream.ReadByte();
+ byte[] message = new byte [msgLength];
+ this.innerStream.Read (message, 0, msgLength);
+
+ int msgType = message [0];
+ if (msgType != 1)
+ {
+ throw new TlsException(AlertDescription.DecodeError);
+ }
+ int protocol = (message [1] << 8 | message [2]);
+ int cipherSpecLength = (message [3] << 8 | message [4]);
+ int sessionIdLength = (message [5] << 8 | message [6]);
+ int challengeLength = (message [7] << 8 | message [8]);
+ int length = (challengeLength > 32) ? 32 : challengeLength;
+
+ // Read CipherSpecs
+ byte[] cipherSpecV2 = new byte[cipherSpecLength];
+ Buffer.BlockCopy (message, 9, cipherSpecV2, 0, cipherSpecLength);
+
+ // Read session ID
+ byte[] sessionId = new byte[sessionIdLength];
+ Buffer.BlockCopy (message, 9 + cipherSpecLength, sessionId, 0, sessionIdLength);
+
+ // Read challenge ID
+ byte[] challenge = new byte[challengeLength];
+ Buffer.BlockCopy (message, 9 + cipherSpecLength + sessionIdLength, challenge, 0, challengeLength);
+
+ if (challengeLength < 16 || cipherSpecLength == 0 || (cipherSpecLength % 3) != 0)
+ {
+ throw new TlsException(AlertDescription.DecodeError);
+ }
+
+ // Updated the Session ID
+ if (sessionId.Length > 0)
+ {
+ this.context.SessionId = sessionId;
+ }
+
+ // Update the protocol version
+ this.Context.ChangeProtocol((short)protocol);
+
+ // Select the Cipher suite
+ this.ProcessCipherSpecV2Buffer(this.Context.SecurityProtocol, cipherSpecV2);
+
+ // Updated the Client Random\r
+ this.context.ClientRandom = new byte [32]; // Always 32\r
+ // 1. if challenge is bigger than 32 bytes only use the last 32 bytes\r
+ // 2. right justify (0) challenge in ClientRandom if less than 32\r
+ Buffer.BlockCopy (challenge, challenge.Length - length, this.context.ClientRandom, 32 - length, length);\r
+\r
+ // Set
+ this.context.LastHandshakeMsg = HandshakeType.ClientHello;
+ this.context.ProtocolNegotiated = true;
+
+ return message;
+ }
+
+ private byte[] ReadStandardRecordBuffer()
+ {
+ short protocol = this.ReadShort();
+ short length = this.ReadShort();
+
+ // Read Record data
+ int received = 0;
+ byte[] buffer = new byte[length];
+ while (received != length)
+ {
+ received += this.innerStream.Read(buffer, received, buffer.Length - received);
+ }
+
+ // Check that the message has a valid protocol version
+ if (protocol != this.context.Protocol && this.context.ProtocolNegotiated)
+ {
+ throw new TlsException(
+ AlertDescription.ProtocolVersion, "Invalid protocol version on message received");
+ }
+
+ DebugHelper.WriteLine("Record data", buffer);
+
+ return buffer;
+ }
+
+ private short ReadShort()
{
byte[] b = new byte[2];
this.innerStream.Read(b, 0, b.Length);
return System.Net.IPAddress.HostToNetworkOrder(val);
}
- private void processAlert(
- AlertLevel alertLevel,
- AlertDescription alertDesc)
+ private void ProcessAlert(AlertLevel alertLevel, AlertDescription alertDesc)
{
switch (alertLevel)
{
}
#endregion
+
+ #region CipherSpecV2 processing
+
+ private void ProcessCipherSpecV2Buffer(SecurityProtocolType protocol, byte[] buffer)
+ {
+ TlsStream codes = new TlsStream(buffer);
+
+ string prefix = (protocol == SecurityProtocolType.Ssl3) ? "SSL_" : "TLS_";
+
+ while (codes.Position < codes.Length)
+ {
+ byte check = codes.ReadByte();
+
+ if (check == 0)
+ {
+ // SSL/TLS cipher spec
+ int index = 0;
+ short code = codes.ReadInt16();
+ if ((index = this.Context.SupportedCiphers.IndexOf(code)) != -1)
+ {
+ this.Context.Cipher = this.Context.SupportedCiphers[index];
+ break;
+ }
+ }
+ else
+ {
+ byte[] tmp = new byte[2];
+ codes.Read(tmp, 0, tmp.Length);
+
+ int tmpCode = ((check & 0xff) << 16) | ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff);
+ CipherSuite cipher = this.MapV2CipherCode(prefix, tmpCode);
+
+ if (cipher != null)
+ {
+ this.Context.Cipher = cipher;
+ break;
+ }
+ }
+ }
+
+ if (this.Context.Cipher == null)
+ {
+ throw new TlsException(AlertDescription.InsuficientSecurity, "Insuficient Security");
+ }
+ }
+
+ private CipherSuite MapV2CipherCode(string prefix, int code)
+ {
+ try
+ {
+ switch (code)
+ {
+ case 65664:
+ // TLS_RC4_128_WITH_MD5
+ return this.Context.SupportedCiphers[prefix + "RSA_WITH_RC4_128_MD5"];
+
+ case 131200:
+ // TLS_RC4_128_EXPORT40_WITH_MD5
+ return this.Context.SupportedCiphers[prefix + "RSA_EXPORT_WITH_RC4_40_MD5"];
+
+ case 196736:
+ // TLS_RC2_CBC_128_CBC_WITH_MD5
+ return this.Context.SupportedCiphers[prefix + "RSA_EXPORT_WITH_RC2_CBC_40_MD5"];
+
+ case 262272:
+ // TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5
+ return this.Context.SupportedCiphers[prefix + "RSA_EXPORT_WITH_RC2_CBC_40_MD5"];
+
+ case 327808:
+ // TLS_IDEA_128_CBC_WITH_MD5
+ return null;
+
+ case 393280:
+ // TLS_DES_64_CBC_WITH_MD5
+ return null;
+
+ case 458944:
+ // TLS_DES_192_EDE3_CBC_WITH_MD5
+ return null;
+
+ default:
+ return null;
+ }
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ #endregion
}
}