You've already forked linux-packaging-mono
Imported Upstream version 6.8.0.73
Former-commit-id: d18deab1b47cfd3ad8cba82b3f37d00eec2170af
This commit is contained in:
parent
bceda29824
commit
73ee7591e8
@@ -96,14 +96,6 @@ namespace Mono.Security.Interface
|
||||
ValidationResult ValidateCertificate (string targetHost, bool serverMode, X509CertificateCollection certificates);
|
||||
}
|
||||
|
||||
internal interface ICertificateValidator2 : ICertificateValidator
|
||||
{
|
||||
/*
|
||||
* Internal use only.
|
||||
*/
|
||||
ValidationResult ValidateCertificate (string targetHost, bool serverMode, X509Certificate leaf, X509Chain chain);
|
||||
}
|
||||
|
||||
public static class CertificateValidationHelper
|
||||
{
|
||||
const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
|
||||
|
||||
@@ -42,59 +42,11 @@ namespace Mono.Security.Interface
|
||||
get;
|
||||
}
|
||||
|
||||
void AuthenticateAsClient (string targetHost);
|
||||
|
||||
void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation);
|
||||
|
||||
void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
void EndAuthenticateAsClient (IAsyncResult asyncResult);
|
||||
|
||||
void AuthenticateAsServer (X509Certificate serverCertificate);
|
||||
|
||||
void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation);
|
||||
|
||||
void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
void EndAuthenticateAsServer (IAsyncResult asyncResult);
|
||||
|
||||
Task AuthenticateAsClientAsync (string targetHost);
|
||||
|
||||
Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation);
|
||||
|
||||
Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
|
||||
|
||||
Task AuthenticateAsServerAsync (X509Certificate serverCertificate);
|
||||
|
||||
Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation);
|
||||
|
||||
Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SSA.SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
|
||||
|
||||
int Read (byte[] buffer, int offset, int count);
|
||||
|
||||
void Write (byte[] buffer);
|
||||
|
||||
void Write (byte[] buffer, int offset, int count);
|
||||
|
||||
IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
int EndRead (IAsyncResult asyncResult);
|
||||
|
||||
IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState);
|
||||
|
||||
void EndWrite (IAsyncResult asyncResult);
|
||||
Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken);
|
||||
|
||||
Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken);
|
||||
|
||||
@@ -215,12 +167,5 @@ namespace Mono.Security.Interface
|
||||
|
||||
Task RenegotiateAsync (CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
interface IMonoSslStream2 : IMonoSslStream
|
||||
{
|
||||
Task AuthenticateAsClientAsync (IMonoSslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken);
|
||||
|
||||
Task AuthenticateAsServerAsync (IMonoSslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,10 +121,6 @@ namespace Mono.Security.Interface
|
||||
Stream innerStream, bool leaveInnerStreamOpen,
|
||||
MonoTlsSettings settings = null);
|
||||
|
||||
internal abstract IMonoSslStream CreateSslStreamInternal (
|
||||
SslStream sslStream, Stream innerStream, bool leaveInnerStreamOpen,
|
||||
MonoTlsSettings settings);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Native Certificate Implementation
|
||||
@@ -133,34 +129,6 @@ namespace Mono.Security.Interface
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal virtual X509Certificate2Impl GetNativeCertificate (
|
||||
byte[] data, string password, X509KeyStorageFlags flags)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
internal virtual X509Certificate2Impl GetNativeCertificate (
|
||||
X509Certificate certificate)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Certificate Validation
|
||||
/*
|
||||
* If @serverMode is true, then we're a server and want to validate a certificate
|
||||
* that we received from a client.
|
||||
*
|
||||
* On OS X and Mobile, the @chain will be initialized with the @certificates, but not actually built.
|
||||
*
|
||||
* Returns `true` if certificate validation has been performed and `false` to invoke the
|
||||
* default system validator.
|
||||
*/
|
||||
internal abstract bool ValidateCertificate (
|
||||
ICertificateValidator2 validator, string targetHost, bool serverMode,
|
||||
X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
|
||||
ref MonoSslPolicyErrors errors, ref int status11);
|
||||
#endregion
|
||||
|
||||
#region Misc
|
||||
|
||||
@@ -183,9 +183,10 @@ namespace Mono.Security.Interface
|
||||
* - 1: everything up until May 2018
|
||||
* - 2: the new ServicePointScheduler changes have landed
|
||||
* - 3: full support for Client Certificates
|
||||
* - 4: Legacy TLS Removal
|
||||
*
|
||||
*/
|
||||
internal const int InternalVersion = 3;
|
||||
internal const int InternalVersion = 4;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// 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.Security.Cryptography.X509Certificates;
|
||||
|
||||
using Mono.Security.Protocol.Tls;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsClientCertificate : HandshakeMessage
|
||||
{
|
||||
private bool clientCertSelected;
|
||||
private X509Certificate clientCert;
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsClientCertificate(Context context)
|
||||
: base(context, HandshakeType.Certificate)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public X509Certificate ClientCertificate {
|
||||
get {
|
||||
if (!clientCertSelected)
|
||||
{
|
||||
GetClientCertificate ();
|
||||
clientCertSelected = true;
|
||||
}
|
||||
return clientCert;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
private void GetClientCertificate ()
|
||||
{
|
||||
// TODO: Client certificate selection is unfinished
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
// note: the server may ask for mutual authentication
|
||||
// but may not require it (i.e. it can be optional).
|
||||
if (context.ClientSettings.Certificates != null &&
|
||||
context.ClientSettings.Certificates.Count > 0)
|
||||
{
|
||||
clientCert = context.SslStream.RaiseClientCertificateSelection(
|
||||
this.Context.ClientSettings.Certificates,
|
||||
new X509Certificate(this.Context.ServerSettings.Certificates[0].RawData),
|
||||
this.Context.ClientSettings.TargetHost,
|
||||
null);
|
||||
// Note: the application code can raise it's
|
||||
// own exception to stop the connection too.
|
||||
}
|
||||
|
||||
// Update the selected client certificate
|
||||
context.ClientSettings.ClientCertificate = clientCert;
|
||||
}
|
||||
|
||||
private void SendCertificates ()
|
||||
{
|
||||
TlsStream chain = new TlsStream ();
|
||||
|
||||
X509Certificate currentCert = this.ClientCertificate;
|
||||
while (currentCert != null) {
|
||||
byte[] rawCert = currentCert.GetRawCertData ();
|
||||
chain.WriteInt24 (rawCert.Length);
|
||||
chain.Write(rawCert);
|
||||
currentCert = FindParentCertificate (currentCert);
|
||||
}
|
||||
this.WriteInt24 ((int)chain.Length);
|
||||
this.Write (chain.ToArray ());
|
||||
}
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
if (this.ClientCertificate != null) {
|
||||
SendCertificates ();
|
||||
} else {
|
||||
// an Alert warning for NoCertificate (41)
|
||||
// should be sent from here - but that would
|
||||
// break the current message handling
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
if (this.ClientCertificate != null) {
|
||||
SendCertificates ();
|
||||
} else {
|
||||
// return message with empty certificate (see 7.4.6 in RFC2246)
|
||||
this.WriteInt24 (0);
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate FindParentCertificate (X509Certificate cert)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
// This certificate is the root certificate
|
||||
if (cert.GetName () == cert.GetIssuerName ())
|
||||
return null;
|
||||
|
||||
foreach (X509Certificate certificate in this.Context.ClientSettings.Certificates) {
|
||||
if (certificate.GetName () == cert.GetIssuerName ())
|
||||
return certificate;
|
||||
}
|
||||
return null;
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
// 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.Security.Cryptography.X509Certificates;
|
||||
|
||||
using System.Security.Cryptography;
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsClientCertificateVerify : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientCertificateVerify(Context context)
|
||||
: base(context, HandshakeType.CertificateVerify)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
AsymmetricAlgorithm privKey = null;
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
privKey = context.SslStream.RaisePrivateKeySelection(
|
||||
context.ClientSettings.ClientCertificate,
|
||||
context.ClientSettings.TargetHost);
|
||||
|
||||
if (privKey == null)
|
||||
{
|
||||
throw new TlsException(AlertDescription.UserCancelled, "Client certificate Private Key unavailable.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SslHandshakeHash hash = new SslHandshakeHash(context.MasterSecret);
|
||||
hash.TransformFinalBlock(
|
||||
context.HandshakeMessages.ToArray(),
|
||||
0,
|
||||
(int)context.HandshakeMessages.Length);
|
||||
|
||||
// CreateSignature uses ((RSA)privKey).DecryptValue which is not implemented
|
||||
// in RSACryptoServiceProvider. Other implementations likely implement DecryptValue
|
||||
// so we will try the CreateSignature method.
|
||||
byte[] signature = null;
|
||||
if (!(privKey is RSACryptoServiceProvider))
|
||||
{
|
||||
try
|
||||
{
|
||||
signature = hash.CreateSignature((RSA)privKey);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{ }
|
||||
}
|
||||
// If DecryptValue is not implemented, then try to export the private
|
||||
// key and let the RSAManaged class do the DecryptValue
|
||||
if (signature == null)
|
||||
{
|
||||
// RSAManaged of the selected ClientCertificate
|
||||
// (at this moment the first one)
|
||||
RSA rsa = this.getClientCertRSA((RSA)privKey);
|
||||
|
||||
// Write message
|
||||
signature = hash.CreateSignature(rsa);
|
||||
}
|
||||
this.Write((short)signature.Length);
|
||||
this.Write(signature, 0, signature.Length);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
AsymmetricAlgorithm privKey = null;
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
privKey = context.SslStream.RaisePrivateKeySelection(
|
||||
context.ClientSettings.ClientCertificate,
|
||||
context.ClientSettings.TargetHost);
|
||||
|
||||
if (privKey == null)
|
||||
{
|
||||
throw new TlsException(AlertDescription.UserCancelled, "Client certificate Private Key unavailable.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute handshake messages hash
|
||||
MD5SHA1 hash = new MD5SHA1();
|
||||
hash.ComputeHash(
|
||||
context.HandshakeMessages.ToArray(),
|
||||
0,
|
||||
(int)context.HandshakeMessages.Length);
|
||||
|
||||
// CreateSignature uses ((RSA)privKey).DecryptValue which is not implemented
|
||||
// in RSACryptoServiceProvider. Other implementations likely implement DecryptValue
|
||||
// so we will try the CreateSignature method.
|
||||
byte[] signature = null;
|
||||
if (!(privKey is RSACryptoServiceProvider))
|
||||
{
|
||||
try
|
||||
{
|
||||
signature = hash.CreateSignature((RSA)privKey);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{ }
|
||||
}
|
||||
// If DecryptValue is not implemented, then try to export the private
|
||||
// key and let the RSAManaged class do the DecryptValue
|
||||
if (signature == null)
|
||||
{
|
||||
// RSAManaged of the selected ClientCertificate
|
||||
// (at this moment the first one)
|
||||
RSA rsa = this.getClientCertRSA((RSA)privKey);
|
||||
|
||||
// Write message
|
||||
signature = hash.CreateSignature(rsa);
|
||||
}
|
||||
this.Write((short)signature.Length);
|
||||
this.Write(signature, 0, signature.Length);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private RSA getClientCertRSA(RSA privKey)
|
||||
{
|
||||
RSAParameters rsaParams = new RSAParameters();
|
||||
RSAParameters privateParams = privKey.ExportParameters(true);
|
||||
|
||||
// for RSA m_publickey contains 2 ASN.1 integers
|
||||
// the modulus and the public exponent
|
||||
ASN1 pubkey = new ASN1 (this.Context.ClientSettings.Certificates[0].GetPublicKey());
|
||||
ASN1 modulus = pubkey [0];
|
||||
if ((modulus == null) || (modulus.Tag != 0x02))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ASN1 exponent = pubkey [1];
|
||||
if (exponent.Tag != 0x02)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
rsaParams.Modulus = this.getUnsignedBigInteger(modulus.Value);
|
||||
rsaParams.Exponent = exponent.Value;
|
||||
|
||||
// Set private key parameters
|
||||
rsaParams.D = privateParams.D;
|
||||
rsaParams.DP = privateParams.DP;
|
||||
rsaParams.DQ = privateParams.DQ;
|
||||
rsaParams.InverseQ = privateParams.InverseQ;
|
||||
rsaParams.P = privateParams.P;
|
||||
rsaParams.Q = privateParams.Q;
|
||||
|
||||
// BUG: MS BCL 1.0 can't import a key which
|
||||
// isn't the same size as the one present in
|
||||
// the container.
|
||||
int keySize = (rsaParams.Modulus.Length << 3);
|
||||
RSAManaged rsa = new RSAManaged(keySize);
|
||||
rsa.ImportParameters (rsaParams);
|
||||
|
||||
return (RSA)rsa;
|
||||
}
|
||||
|
||||
private byte[] getUnsignedBigInteger(byte[] integer)
|
||||
{
|
||||
if (integer [0] == 0x00)
|
||||
{
|
||||
// this first byte is added so we're sure it's an unsigned integer
|
||||
// however we can't feed it into RSAParameters or DSAParameters
|
||||
int length = integer.Length - 1;
|
||||
byte[] uinteger = new byte [length];
|
||||
Buffer.BlockCopy (integer, 1, uinteger, 0, length);
|
||||
return uinteger;
|
||||
}
|
||||
else
|
||||
{
|
||||
return integer;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsClientFinished : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientFinished(Context context)
|
||||
: base(context, HandshakeType.Finished)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
static private byte[] Ssl3Marker = new byte [4] { 0x43, 0x4c, 0x4e, 0x54 };
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
// Compute handshake messages hashes
|
||||
HashAlgorithm hash = new SslHandshakeHash(this.Context.MasterSecret);
|
||||
|
||||
byte[] data = this.Context.HandshakeMessages.ToArray ();
|
||||
hash.TransformBlock (data, 0, data.Length, data, 0);
|
||||
hash.TransformBlock (Ssl3Marker, 0, Ssl3Marker.Length, Ssl3Marker, 0);
|
||||
// hack to avoid memory allocation
|
||||
hash.TransformFinalBlock (CipherSuite.EmptyArray, 0, 0);
|
||||
|
||||
this.Write (hash.Hash);
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
// Compute handshake messages hash
|
||||
HashAlgorithm hash = new MD5SHA1();
|
||||
|
||||
// note: we could call HashAlgorithm.ComputeHash(Stream) but that would allocate (on Mono)
|
||||
// a 4096 bytes buffer to process the hash - which is bigger than HandshakeMessages
|
||||
byte[] data = this.Context.HandshakeMessages.ToArray ();
|
||||
byte[] digest = hash.ComputeHash (data, 0, data.Length);
|
||||
|
||||
// Write message
|
||||
Write(this.Context.Write.Cipher.PRF(this.Context.MasterSecret, "client finished", digest, 12));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
// 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.Net;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsClientHello : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private byte[] random;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsClientHello(Context context)
|
||||
: base(context, HandshakeType.ClientHello)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
base.Update();
|
||||
|
||||
context.ClientRandom = random;
|
||||
context.ClientHelloProtocol = this.Context.Protocol;
|
||||
|
||||
random = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
// Client Version
|
||||
this.Write(this.Context.Protocol);
|
||||
|
||||
// Random bytes - Unix time + Radom bytes [28]
|
||||
TlsStream clientRandom = new TlsStream();
|
||||
clientRandom.Write(this.Context.GetUnixTime());
|
||||
clientRandom.Write(this.Context.GetSecureRandomBytes(28));
|
||||
this.random = clientRandom.ToArray();
|
||||
clientRandom.Reset();
|
||||
|
||||
this.Write(this.random);
|
||||
|
||||
// Session id
|
||||
// Check if we have a cache session we could reuse
|
||||
this.Context.SessionId = ClientSessionCache.FromHost (this.Context.ClientSettings.TargetHost);
|
||||
if (this.Context.SessionId != null)
|
||||
{
|
||||
this.Write((byte)this.Context.SessionId.Length);
|
||||
if (this.Context.SessionId.Length > 0)
|
||||
{
|
||||
this.Write(this.Context.SessionId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Write((byte)0);
|
||||
}
|
||||
|
||||
// Write length of Cipher suites
|
||||
this.Write((short)(this.Context.SupportedCiphers.Count*2));
|
||||
|
||||
// Write Supported Cipher suites
|
||||
for (int i = 0; i < this.Context.SupportedCiphers.Count; i++)
|
||||
{
|
||||
this.Write((short)this.Context.SupportedCiphers[i].Code);
|
||||
}
|
||||
|
||||
// Compression methods length
|
||||
this.Write((byte)1);
|
||||
|
||||
// Compression methods ( 0 = none )
|
||||
this.Write((byte)this.Context.CompressionMethod);
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
ProcessAsSsl3 ();
|
||||
|
||||
// If applicable add the "server_name" extension to the hello message
|
||||
// http://www.ietf.org/rfc/rfc3546.txt
|
||||
string host = Context.ClientSettings.TargetHost;
|
||||
// Our TargetHost might be an address (not a host *name*) - see bug #8553
|
||||
// RFC3546 -> Literal IPv4 and IPv6 addresses are not permitted in "HostName".
|
||||
IPAddress addr;
|
||||
if (IPAddress.TryParse (host, out addr))
|
||||
return;
|
||||
|
||||
TlsStream extensions = new TlsStream ();
|
||||
byte[] server_name = System.Text.Encoding.UTF8.GetBytes (host);
|
||||
extensions.Write ((short) 0x0000); // ExtensionType: server_name (0)
|
||||
extensions.Write ((short) (server_name.Length + 5)); // ServerNameList (length)
|
||||
extensions.Write ((short) (server_name.Length + 3)); // ServerName (length)
|
||||
extensions.Write ((byte) 0x00); // NameType: host_name (0)
|
||||
extensions.Write ((short) server_name.Length); // HostName (length)
|
||||
extensions.Write (server_name); // HostName (UTF8)
|
||||
this.Write ((short) extensions.Length);
|
||||
this.Write (extensions.ToArray ());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsClientKeyExchange : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientKeyExchange (Context context) :
|
||||
base(context, HandshakeType.ClientKeyExchange)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
// a large chunk of code is common to both SSL3 and TLS1
|
||||
// SSL3 doesn't send the length of the buffer
|
||||
ProcessCommon (false);
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
// a large chunk of code is common to both SSL3 and TLS1
|
||||
// TLS1 does send the length of the buffer
|
||||
ProcessCommon (true);
|
||||
}
|
||||
|
||||
public void ProcessCommon (bool sendLength)
|
||||
{
|
||||
// Compute pre master secret
|
||||
byte[] preMasterSecret = this.Context.Negotiating.Cipher.CreatePremasterSecret ();
|
||||
|
||||
// Create a new RSA key
|
||||
RSA rsa = null;
|
||||
if (this.Context.ServerSettings.ServerKeyExchange)
|
||||
{
|
||||
// this is the case for "exportable" ciphers
|
||||
rsa = new RSAManaged ();
|
||||
rsa.ImportParameters (this.Context.ServerSettings.RsaParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
rsa = this.Context.ServerSettings.CertificateRSA;
|
||||
}
|
||||
|
||||
// Encrypt premaster_sercret
|
||||
RSAPKCS1KeyExchangeFormatter formatter = new RSAPKCS1KeyExchangeFormatter (rsa);
|
||||
|
||||
// Write the preMasterSecret encrypted
|
||||
byte[] buffer = formatter.CreateKeyExchange (preMasterSecret);
|
||||
if (sendLength)
|
||||
this.Write ((short) buffer.Length);
|
||||
this.Write (buffer);
|
||||
|
||||
// Create master secret
|
||||
this.Context.Negotiating.Cipher.ComputeMasterSecret (preMasterSecret);
|
||||
|
||||
// Create keys
|
||||
this.Context.Negotiating.Cipher.ComputeKeys ();
|
||||
|
||||
// Clear resources
|
||||
rsa.Clear ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,450 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2004, 2006-2010 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Net;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Security.Cryptography;
|
||||
using X509Cert = System.Security.Cryptography.X509Certificates;
|
||||
|
||||
using Mono.Security.X509;
|
||||
using Mono.Security.X509.Extensions;
|
||||
|
||||
using Mono.Security.Interface;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsServerCertificate : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private X509CertificateCollection certificates;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsServerCertificate(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.Certificate, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
this.Context.ServerSettings.Certificates = this.certificates;
|
||||
this.Context.ServerSettings.UpdateCertificateRSA();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
this.certificates = new X509CertificateCollection();
|
||||
|
||||
int readed = 0;
|
||||
int length = this.ReadInt24();
|
||||
|
||||
while (readed < length)
|
||||
{
|
||||
// Read certificate length
|
||||
int certLength = ReadInt24();
|
||||
|
||||
// Increment readed
|
||||
readed += 3;
|
||||
|
||||
if (certLength > 0)
|
||||
{
|
||||
// Read certificate data
|
||||
byte[] buffer = this.ReadBytes(certLength);
|
||||
|
||||
// Create a new X509 Certificate
|
||||
X509Certificate certificate = new X509Certificate(buffer);
|
||||
certificates.Add(certificate);
|
||||
|
||||
readed += certLength;
|
||||
|
||||
DebugHelper.WriteLine(
|
||||
String.Format("Server Certificate {0}", certificates.Count),
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
this.validateCertificates(certificates);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
// Note: this method only works for RSA certificates
|
||||
// DH certificates requires some changes - does anyone use one ?
|
||||
private bool checkCertificateUsage (X509Certificate cert)
|
||||
{
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
// certificate extensions are required for this
|
||||
// we "must" accept older certificates without proofs
|
||||
if (cert.Version < 3)
|
||||
return true;
|
||||
|
||||
KeyUsages ku = KeyUsages.none;
|
||||
switch (context.Negotiating.Cipher.ExchangeAlgorithmType)
|
||||
{
|
||||
case ExchangeAlgorithmType.RsaSign:
|
||||
ku = KeyUsages.digitalSignature;
|
||||
break;
|
||||
case ExchangeAlgorithmType.RsaKeyX:
|
||||
ku = KeyUsages.keyEncipherment;
|
||||
break;
|
||||
case ExchangeAlgorithmType.DiffieHellman:
|
||||
ku = KeyUsages.keyAgreement;
|
||||
break;
|
||||
case ExchangeAlgorithmType.Fortezza:
|
||||
return false; // unsupported certificate type
|
||||
}
|
||||
|
||||
KeyUsageExtension kux = null;
|
||||
ExtendedKeyUsageExtension eku = null;
|
||||
|
||||
X509Extension xtn = cert.Extensions ["2.5.29.15"];
|
||||
if (xtn != null)
|
||||
kux = new KeyUsageExtension (xtn);
|
||||
|
||||
xtn = cert.Extensions ["2.5.29.37"];
|
||||
if (xtn != null)
|
||||
eku = new ExtendedKeyUsageExtension (xtn);
|
||||
|
||||
if ((kux != null) && (eku != null))
|
||||
{
|
||||
// RFC3280 states that when both KeyUsageExtension and
|
||||
// ExtendedKeyUsageExtension are present then BOTH should
|
||||
// be valid
|
||||
if (!kux.Support (ku))
|
||||
return false;
|
||||
return (eku.KeyPurpose.Contains ("1.3.6.1.5.5.7.3.1") ||
|
||||
eku.KeyPurpose.Contains ("2.16.840.1.113730.4.1"));
|
||||
}
|
||||
else if (kux != null)
|
||||
{
|
||||
return kux.Support (ku);
|
||||
}
|
||||
else if (eku != null)
|
||||
{
|
||||
// Server Authentication (1.3.6.1.5.5.7.3.1) or
|
||||
// Netscape Server Gated Crypto (2.16.840.1.113730.4)
|
||||
return (eku.KeyPurpose.Contains ("1.3.6.1.5.5.7.3.1") ||
|
||||
eku.KeyPurpose.Contains ("2.16.840.1.113730.4.1"));
|
||||
}
|
||||
|
||||
// last chance - try with older (deprecated) Netscape extensions
|
||||
xtn = cert.Extensions ["2.16.840.1.113730.1.1"];
|
||||
if (xtn != null)
|
||||
{
|
||||
NetscapeCertTypeExtension ct = new NetscapeCertTypeExtension (xtn);
|
||||
return ct.Support (NetscapeCertTypeExtension.CertTypes.SslServer);
|
||||
}
|
||||
|
||||
// if the CN=host (checked later) then we assume this is meant for SSL/TLS
|
||||
// e.g. the new smtp.gmail.com certificate
|
||||
return true;
|
||||
}
|
||||
|
||||
private void validateCertificates(X509CertificateCollection certificates)
|
||||
{
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
AlertDescription description = AlertDescription.BadCertificate;
|
||||
|
||||
#if INSIDE_SYSTEM
|
||||
// This helps the linker to remove a lot of validation code that will never be used since
|
||||
// System.dll will, for OSX and iOS, uses the operating system X.509 certificate validations
|
||||
RemoteValidation (context, description);
|
||||
#else
|
||||
if (context.SslStream.HaveRemoteValidation2Callback)
|
||||
RemoteValidation (context, description);
|
||||
else
|
||||
LocalValidation (context, description);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RemoteValidation (ClientContext context, AlertDescription description)
|
||||
{
|
||||
ValidationResult res = context.SslStream.RaiseServerCertificateValidation2 (certificates);
|
||||
if (res.Trusted)
|
||||
return;
|
||||
|
||||
long error = res.ErrorCode;
|
||||
switch (error) {
|
||||
case 0x800B0101:
|
||||
description = AlertDescription.CertificateExpired;
|
||||
break;
|
||||
case 0x800B010A:
|
||||
description = AlertDescription.UnknownCA;
|
||||
break;
|
||||
case 0x800B0109:
|
||||
description = AlertDescription.UnknownCA;
|
||||
break;
|
||||
default:
|
||||
description = AlertDescription.CertificateUnknown;
|
||||
break;
|
||||
}
|
||||
string err = String.Format ("Invalid certificate received from server. Error code: 0x{0:x}", error);
|
||||
throw new TlsException (description, err);
|
||||
}
|
||||
|
||||
void LocalValidation (ClientContext context, AlertDescription description)
|
||||
{
|
||||
// the leaf is the web server certificate
|
||||
X509Certificate leaf = certificates [0];
|
||||
X509Cert.X509Certificate cert = new X509Cert.X509Certificate (leaf.RawData);
|
||||
|
||||
ArrayList errors = new ArrayList();
|
||||
|
||||
// SSL specific check - not all certificates can be
|
||||
// used to server-side SSL some rules applies after
|
||||
// all ;-)
|
||||
if (!checkCertificateUsage (leaf))
|
||||
{
|
||||
// WinError.h CERT_E_PURPOSE 0x800B0106
|
||||
errors.Add ((int)-2146762490);
|
||||
}
|
||||
|
||||
// SSL specific check - does the certificate match
|
||||
// the host ?
|
||||
if (!checkServerIdentity (leaf))
|
||||
{
|
||||
// WinError.h CERT_E_CN_NO_MATCH 0x800B010F
|
||||
errors.Add ((int)-2146762481);
|
||||
}
|
||||
|
||||
// Note: building and verifying a chain can take much time
|
||||
// so we do it last (letting simple things fails first)
|
||||
|
||||
// Note: In TLS the certificates MUST be in order (and
|
||||
// optionally include the root certificate) so we're not
|
||||
// building the chain using LoadCertificate (it's faster)
|
||||
|
||||
// Note: IIS doesn't seem to send the whole certificate chain
|
||||
// but only the server certificate :-( it's assuming that you
|
||||
// already have this chain installed on your computer. duh!
|
||||
// http://groups.google.ca/groups?q=IIS+server+certificate+chain&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=85058s%24avd%241%40nnrp1.deja.com&rnum=3
|
||||
|
||||
// we must remove the leaf certificate from the chain
|
||||
X509CertificateCollection chain = new X509CertificateCollection (certificates);
|
||||
chain.Remove (leaf);
|
||||
X509Chain verify = new X509Chain (chain);
|
||||
|
||||
bool result = false;
|
||||
|
||||
try
|
||||
{
|
||||
result = verify.Build (leaf);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
switch (verify.Status)
|
||||
{
|
||||
case X509ChainStatusFlags.InvalidBasicConstraints:
|
||||
// WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019
|
||||
errors.Add ((int)-2146869223);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotSignatureValid:
|
||||
// WinError.h TRUST_E_BAD_DIGEST 0x80096010
|
||||
errors.Add ((int)-2146869232);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotTimeNested:
|
||||
// WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102
|
||||
errors.Add ((int)-2146762494);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotTimeValid:
|
||||
// WinError.h CERT_E_EXPIRED 0x800B0101
|
||||
description = AlertDescription.CertificateExpired;
|
||||
errors.Add ((int)-2146762495);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.PartialChain:
|
||||
// WinError.h CERT_E_CHAINING 0x800B010A
|
||||
description = AlertDescription.UnknownCA;
|
||||
errors.Add ((int)-2146762486);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.UntrustedRoot:
|
||||
// WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109
|
||||
description = AlertDescription.UnknownCA;
|
||||
errors.Add ((int)-2146762487);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown error
|
||||
description = AlertDescription.CertificateUnknown;
|
||||
errors.Add ((int)verify.Status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int[] certificateErrors = (int[])errors.ToArray(typeof(int));
|
||||
|
||||
if (!context.SslStream.RaiseServerCertificateValidation(
|
||||
cert,
|
||||
certificateErrors))
|
||||
{
|
||||
throw new TlsException(
|
||||
description,
|
||||
"Invalid certificate received from server.");
|
||||
}
|
||||
}
|
||||
|
||||
// RFC2818 - HTTP Over TLS, Section 3.1
|
||||
// http://www.ietf.org/rfc/rfc2818.txt
|
||||
//
|
||||
// 1. if present MUST use subjectAltName dNSName as identity
|
||||
// 1.1. if multiples entries a match of any one is acceptable
|
||||
// 1.2. wildcard * is acceptable
|
||||
// 2. URI may be an IP address -> subjectAltName.iPAddress
|
||||
// 2.1. exact match is required
|
||||
// 3. Use of the most specific Common Name (CN=) in the Subject
|
||||
// 3.1 Existing practice but DEPRECATED
|
||||
private bool checkServerIdentity (X509Certificate cert)
|
||||
{
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
string targetHost = context.ClientSettings.TargetHost;
|
||||
|
||||
X509Extension ext = cert.Extensions ["2.5.29.17"];
|
||||
// 1. subjectAltName
|
||||
if (ext != null)
|
||||
{
|
||||
SubjectAltNameExtension subjectAltName = new SubjectAltNameExtension (ext);
|
||||
// 1.1 - multiple dNSName
|
||||
foreach (string dns in subjectAltName.DNSNames)
|
||||
{
|
||||
// 1.2 TODO - wildcard support
|
||||
if (Match (targetHost, dns))
|
||||
return true;
|
||||
}
|
||||
// 2. ipAddress
|
||||
foreach (string ip in subjectAltName.IPAddresses)
|
||||
{
|
||||
// 2.1. Exact match required
|
||||
if (ip == targetHost)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 3. Common Name (CN=)
|
||||
return checkDomainName (cert.SubjectName);
|
||||
}
|
||||
|
||||
private bool checkDomainName(string subjectName)
|
||||
{
|
||||
ClientContext context = (ClientContext)this.Context;
|
||||
|
||||
string domainName = String.Empty;
|
||||
Regex search = new Regex(@"CN\s*=\s*([^,]*)");
|
||||
|
||||
MatchCollection elements = search.Matches(subjectName);
|
||||
|
||||
if (elements.Count == 1)
|
||||
{
|
||||
if (elements[0].Success)
|
||||
{
|
||||
domainName = elements[0].Groups[1].Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return Match (context.ClientSettings.TargetHost, domainName);
|
||||
}
|
||||
|
||||
// ensure the pattern is valid wrt to RFC2595 and RFC2818
|
||||
// http://www.ietf.org/rfc/rfc2595.txt
|
||||
// http://www.ietf.org/rfc/rfc2818.txt
|
||||
static bool Match (string hostname, string pattern)
|
||||
{
|
||||
// check if this is a pattern
|
||||
int index = pattern.IndexOf ('*');
|
||||
if (index == -1) {
|
||||
// not a pattern, do a direct case-insensitive comparison
|
||||
return (String.Compare (hostname, pattern, true, CultureInfo.InvariantCulture) == 0);
|
||||
}
|
||||
|
||||
// check pattern validity
|
||||
// A "*" wildcard character MAY be used as the left-most name component in the certificate.
|
||||
|
||||
// unless this is the last char (valid)
|
||||
if (index != pattern.Length - 1) {
|
||||
// then the next char must be a dot .'.
|
||||
if (pattern [index + 1] != '.')
|
||||
return false;
|
||||
}
|
||||
|
||||
// only one (A) wildcard is supported
|
||||
int i2 = pattern.IndexOf ('*', index + 1);
|
||||
if (i2 != -1)
|
||||
return false;
|
||||
|
||||
// match the end of the pattern
|
||||
string end = pattern.Substring (index + 1);
|
||||
int length = hostname.Length - end.Length;
|
||||
// no point to check a pattern that is longer than the hostname
|
||||
if (length <= 0)
|
||||
return false;
|
||||
|
||||
if (String.Compare (hostname, length, end, 0, end.Length, true, CultureInfo.InvariantCulture) != 0)
|
||||
return false;
|
||||
|
||||
// special case, we start with the wildcard
|
||||
if (index == 0) {
|
||||
// ensure we hostname non-matched part (start) doesn't contain a dot
|
||||
int i3 = hostname.IndexOf ('.');
|
||||
return ((i3 == -1) || (i3 >= (hostname.Length - end.Length)));
|
||||
}
|
||||
|
||||
// match the start of the pattern
|
||||
string start = pattern.Substring (0, index);
|
||||
return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// 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;
|
||||
using Mono.Security;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsServerCertificateRequest : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private ClientCertificateType[] certificateTypes;
|
||||
private string[] distinguisedNames;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsServerCertificateRequest(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.CertificateRequest, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
this.Context.ServerSettings.CertificateTypes = this.certificateTypes;
|
||||
this.Context.ServerSettings.DistinguisedNames = this.distinguisedNames;
|
||||
this.Context.ServerSettings.CertificateRequest = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
// Read requested certificate types
|
||||
int typesCount = this.ReadByte();
|
||||
|
||||
this.certificateTypes = new ClientCertificateType[typesCount];
|
||||
|
||||
for (int i = 0; i < typesCount; i++)
|
||||
{
|
||||
this.certificateTypes[i] = (ClientCertificateType)this.ReadByte();
|
||||
}
|
||||
|
||||
/*
|
||||
* Read requested certificate authorities (Distinguised Names)
|
||||
*
|
||||
* Name ::= SEQUENCE OF RelativeDistinguishedName
|
||||
*
|
||||
* RelativeDistinguishedName ::= SET OF AttributeValueAssertion
|
||||
*
|
||||
* AttributeValueAssertion ::= SEQUENCE {
|
||||
* attributeType OBJECT IDENTIFIER
|
||||
* attributeValue ANY }
|
||||
*/
|
||||
if (this.ReadInt16() != 0)
|
||||
{
|
||||
ASN1 rdn = new ASN1(this.ReadBytes(this.ReadInt16()));
|
||||
|
||||
distinguisedNames = new string[rdn.Count];
|
||||
|
||||
for (int i = 0; i < rdn.Count; i++)
|
||||
{
|
||||
// element[0] = attributeType
|
||||
// element[1] = attributeValue
|
||||
ASN1 element = new ASN1(rdn[i].Value);
|
||||
|
||||
distinguisedNames[i] = Encoding.UTF8.GetString(element[1].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsServerFinished : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsServerFinished(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.Finished, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// Hahdshake is finished
|
||||
this.Context.HandshakeState = HandshakeState.Finished;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
static private byte[] Ssl3Marker = new byte [4] { 0x53, 0x52, 0x56, 0x52 };
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
// Compute handshake messages hashes
|
||||
HashAlgorithm hash = new SslHandshakeHash(this.Context.MasterSecret);
|
||||
|
||||
byte[] data = this.Context.HandshakeMessages.ToArray ();
|
||||
hash.TransformBlock (data, 0, data.Length, data, 0);
|
||||
hash.TransformBlock (Ssl3Marker, 0, Ssl3Marker.Length, Ssl3Marker, 0);
|
||||
// hack to avoid memory allocation
|
||||
hash.TransformFinalBlock (CipherSuite.EmptyArray, 0, 0);
|
||||
|
||||
byte[] serverHash = this.ReadBytes((int)Length);
|
||||
byte[] clientHash = hash.Hash;
|
||||
|
||||
// Check server prf against client prf
|
||||
if (!Compare (clientHash, serverHash))
|
||||
{
|
||||
// TODO: Review that selected alert is correct
|
||||
throw new TlsException(AlertDescription.InsuficientSecurity, "Invalid ServerFinished message received.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
byte[] serverPRF = this.ReadBytes((int)Length);
|
||||
HashAlgorithm hash = new MD5SHA1();
|
||||
|
||||
// note: we could call HashAlgorithm.ComputeHash(Stream) but that would allocate (on Mono)
|
||||
// a 4096 bytes buffer to process the hash - which is bigger than HandshakeMessages
|
||||
byte[] data = this.Context.HandshakeMessages.ToArray ();
|
||||
byte[] digest = hash.ComputeHash (data, 0, data.Length);
|
||||
|
||||
byte[] clientPRF = this.Context.Current.Cipher.PRF(this.Context.MasterSecret, "server finished", digest, 12);
|
||||
|
||||
// Check server prf against client prf
|
||||
if (!Compare (clientPRF, serverPRF))
|
||||
{
|
||||
throw new TlsException("Invalid ServerFinished message received.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Handshake.Client
|
||||
{
|
||||
internal class TlsServerHello : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private SecurityCompressionType compressionMethod;
|
||||
private byte[] random;
|
||||
private byte[] sessionId;
|
||||
private CipherSuite cipherSuite;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsServerHello(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.ServerHello, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
this.Context.SessionId = this.sessionId;
|
||||
this.Context.ServerRandom = this.random;
|
||||
this.Context.Negotiating.Cipher = this.cipherSuite;
|
||||
this.Context.CompressionMethod = this.compressionMethod;
|
||||
this.Context.ProtocolNegotiated = true;
|
||||
|
||||
DebugHelper.WriteLine("Selected Cipher Suite {0}", this.cipherSuite.Name);
|
||||
DebugHelper.WriteLine("Client random", this.Context.ClientRandom);
|
||||
DebugHelper.WriteLine("Server random", this.Context.ServerRandom);
|
||||
|
||||
// Compute ClientRandom + ServerRandom
|
||||
int clen = this.Context.ClientRandom.Length;
|
||||
int slen = this.Context.ServerRandom.Length;
|
||||
int rlen = clen + slen;
|
||||
byte[] cs = new byte[rlen];
|
||||
Buffer.BlockCopy (this.Context.ClientRandom, 0, cs, 0, clen);
|
||||
Buffer.BlockCopy (this.Context.ServerRandom, 0, cs, clen, slen);
|
||||
this.Context.RandomCS = cs;
|
||||
|
||||
// Server Random + Client Random
|
||||
byte[] sc = new byte[rlen];
|
||||
Buffer.BlockCopy (this.Context.ServerRandom, 0, sc, 0, slen);
|
||||
Buffer.BlockCopy (this.Context.ClientRandom, 0, sc, slen, clen);
|
||||
this.Context.RandomSC = sc;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
// Read protocol version
|
||||
this.processProtocol(this.ReadInt16());
|
||||
|
||||
// Read random - Unix time + Random bytes
|
||||
this.random = this.ReadBytes(32);
|
||||
|
||||
// Read Session id
|
||||
int length = (int) ReadByte ();
|
||||
if (length > 0)
|
||||
{
|
||||
this.sessionId = this.ReadBytes(length);
|
||||
ClientSessionCache.Add (this.Context.ClientSettings.TargetHost, this.sessionId);
|
||||
this.Context.AbbreviatedHandshake = Compare (this.sessionId, this.Context.SessionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Context.AbbreviatedHandshake = false;
|
||||
}
|
||||
|
||||
// Read cipher suite
|
||||
short cipherCode = this.ReadInt16();
|
||||
if (this.Context.SupportedCiphers.IndexOf(cipherCode) == -1)
|
||||
{
|
||||
// The server has sent an invalid ciphersuite
|
||||
throw new TlsException(AlertDescription.InsuficientSecurity, "Invalid cipher suite received from server");
|
||||
}
|
||||
this.cipherSuite = this.Context.SupportedCiphers[cipherCode];
|
||||
|
||||
// Read compression methods ( always 0 )
|
||||
this.compressionMethod = (SecurityCompressionType)this.ReadByte();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void processProtocol(short protocol)
|
||||
{
|
||||
SecurityProtocolType serverProtocol = this.Context.DecodeProtocolCode(protocol);
|
||||
|
||||
if ((serverProtocol & this.Context.SecurityProtocolFlags) == serverProtocol ||
|
||||
(this.Context.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
|
||||
{
|
||||
this.Context.SecurityProtocol = serverProtocol;
|
||||
this.Context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers (false, serverProtocol);
|
||||
|
||||
DebugHelper.WriteLine("Selected protocol {0}", serverProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TlsException(
|
||||
AlertDescription.ProtocolVersion,
|
||||
"Incorrect protocol version received from server");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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.Handshake.Client
|
||||
{
|
||||
internal class TlsServerHelloDone : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsServerHelloDone(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.ServerHelloDone, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
using Mono.Security.X509;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Client
|
||||
{
|
||||
internal class TlsServerKeyExchange : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private RSAParameters rsaParams;
|
||||
private byte[] signedParams;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsServerKeyExchange(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.ServerKeyExchange, buffer)
|
||||
{
|
||||
this.verifySignature();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
this.Context.ServerSettings.ServerKeyExchange = true;
|
||||
this.Context.ServerSettings.RsaParameters = this.rsaParams;
|
||||
this.Context.ServerSettings.SignedParams = this.signedParams;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
this.rsaParams = new RSAParameters();
|
||||
|
||||
// Read modulus
|
||||
this.rsaParams.Modulus = this.ReadBytes(this.ReadInt16());
|
||||
|
||||
// Read exponent
|
||||
this.rsaParams.Exponent = this.ReadBytes(this.ReadInt16());
|
||||
|
||||
// Read signed params
|
||||
this.signedParams = this.ReadBytes(this.ReadInt16());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void verifySignature()
|
||||
{
|
||||
MD5SHA1 hash = new MD5SHA1();
|
||||
|
||||
// Calculate size of server params
|
||||
int size = rsaParams.Modulus.Length + rsaParams.Exponent.Length + 4;
|
||||
|
||||
// Create server params array
|
||||
TlsStream stream = new TlsStream();
|
||||
|
||||
stream.Write(this.Context.RandomCS);
|
||||
stream.Write(this.ToArray(), 0, size);
|
||||
|
||||
hash.ComputeHash(stream.ToArray());
|
||||
|
||||
stream.Reset();
|
||||
|
||||
bool isValidSignature = hash.VerifySignature(
|
||||
this.Context.ServerSettings.CertificateRSA,
|
||||
this.signedParams);
|
||||
|
||||
if (!isValidSignature)
|
||||
{
|
||||
throw new TlsException(
|
||||
AlertDescription.DecodeError,
|
||||
"Data was not signed with the server certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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 SSCX = System.Security.Cryptography.X509Certificates;
|
||||
using Mono.Security.X509;
|
||||
using Mono.Security.X509.Extensions;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Server
|
||||
{
|
||||
internal class TlsClientCertificate : HandshakeMessage
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private X509CertificateCollection clientCertificates;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsClientCertificate(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.Certificate, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
foreach (X509Certificate certificate in clientCertificates) {
|
||||
this.Context.ClientSettings.Certificates.Add (new SSCX.X509Certificate (certificate.RawData));
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCertificate {
|
||||
get { return clientCertificates.Count > 0; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
int bytesRead = 0;
|
||||
int length = this.ReadInt24 ();
|
||||
this.clientCertificates = new X509CertificateCollection ();
|
||||
while (length > bytesRead) {
|
||||
int certLength = this.ReadInt24 ();
|
||||
bytesRead += certLength + 3;
|
||||
byte[] cert = this.ReadBytes (certLength);
|
||||
this.clientCertificates.Add (new X509Certificate (cert));
|
||||
}
|
||||
|
||||
if (this.clientCertificates.Count > 0)
|
||||
{
|
||||
this.validateCertificates (this.clientCertificates);
|
||||
}
|
||||
else if ((this.Context as ServerContext).ClientCertificateRequired)
|
||||
{
|
||||
throw new TlsException (AlertDescription.NoCertificate);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private bool checkCertificateUsage (X509Certificate cert)
|
||||
{
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
|
||||
// certificate extensions are required for this
|
||||
// we "must" accept older certificates without proofs
|
||||
if (cert.Version < 3)
|
||||
return true;
|
||||
|
||||
KeyUsages ku = KeyUsages.none;
|
||||
switch (context.Negotiating.Cipher.ExchangeAlgorithmType)
|
||||
{
|
||||
case ExchangeAlgorithmType.RsaSign:
|
||||
case ExchangeAlgorithmType.RsaKeyX:
|
||||
ku = KeyUsages.digitalSignature;
|
||||
break;
|
||||
case ExchangeAlgorithmType.DiffieHellman:
|
||||
ku = KeyUsages.keyAgreement;
|
||||
break;
|
||||
case ExchangeAlgorithmType.Fortezza:
|
||||
return false; // unsupported certificate type
|
||||
}
|
||||
|
||||
KeyUsageExtension kux = null;
|
||||
ExtendedKeyUsageExtension eku = null;
|
||||
|
||||
X509Extension xtn = cert.Extensions["2.5.29.15"];
|
||||
if (xtn != null)
|
||||
kux = new KeyUsageExtension (xtn);
|
||||
|
||||
xtn = cert.Extensions["2.5.29.37"];
|
||||
if (xtn != null)
|
||||
eku = new ExtendedKeyUsageExtension (xtn);
|
||||
|
||||
if ((kux != null) && (eku != null))
|
||||
{
|
||||
// RFC3280 states that when both KeyUsageExtension and
|
||||
// ExtendedKeyUsageExtension are present then BOTH should
|
||||
// be valid
|
||||
return (kux.Support (ku) &&
|
||||
eku.KeyPurpose.Contains ("1.3.6.1.5.5.7.3.2"));
|
||||
}
|
||||
else if (kux != null)
|
||||
{
|
||||
return kux.Support (ku);
|
||||
}
|
||||
else if (eku != null)
|
||||
{
|
||||
// Client Authentication (1.3.6.1.5.5.7.3.2)
|
||||
return eku.KeyPurpose.Contains ("1.3.6.1.5.5.7.3.2");
|
||||
}
|
||||
|
||||
// last chance - try with older (deprecated) Netscape extensions
|
||||
xtn = cert.Extensions["2.16.840.1.113730.1.1"];
|
||||
if (xtn != null)
|
||||
{
|
||||
NetscapeCertTypeExtension ct = new NetscapeCertTypeExtension (xtn);
|
||||
return ct.Support (NetscapeCertTypeExtension.CertTypes.SslClient);
|
||||
}
|
||||
|
||||
// certificate isn't valid for SSL server usage
|
||||
return false;
|
||||
}
|
||||
|
||||
private void validateCertificates (X509CertificateCollection certificates)
|
||||
{
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
AlertDescription description = AlertDescription.BadCertificate;
|
||||
SSCX.X509Certificate client = null;
|
||||
int[] certificateErrors = null;
|
||||
|
||||
// note: certificate may be null is no certificate is sent
|
||||
// (e.g. optional mutual authentication)
|
||||
if (certificates.Count > 0) {
|
||||
X509Certificate leaf = certificates[0];
|
||||
|
||||
ArrayList errors = new ArrayList ();
|
||||
|
||||
// SSL specific check - not all certificates can be
|
||||
// used to server-side SSL some rules applies after
|
||||
// all ;-)
|
||||
if (!checkCertificateUsage (leaf))
|
||||
{
|
||||
// WinError.h CERT_E_PURPOSE 0x800B0106
|
||||
errors.Add ((int)-2146762490);
|
||||
}
|
||||
|
||||
X509Chain verify;
|
||||
// was a chain supplied ? if so use it, if not
|
||||
if (certificates.Count > 1) {
|
||||
// if so use it (and don't build our own)
|
||||
X509CertificateCollection chain = new X509CertificateCollection (certificates);
|
||||
chain.Remove (leaf);
|
||||
verify = new X509Chain (chain);
|
||||
} else {
|
||||
// if not, then let's build our own (based on what's available in the stores)
|
||||
verify = new X509Chain ();
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
try
|
||||
{
|
||||
result = verify.Build (leaf);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
switch (verify.Status)
|
||||
{
|
||||
case X509ChainStatusFlags.InvalidBasicConstraints:
|
||||
// WinError.h TRUST_E_BASIC_CONSTRAINTS 0x80096019
|
||||
errors.Add ((int)-2146869223);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotSignatureValid:
|
||||
// WinError.h TRUST_E_BAD_DIGEST 0x80096010
|
||||
errors.Add ((int)-2146869232);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotTimeNested:
|
||||
// WinError.h CERT_E_VALIDITYPERIODNESTING 0x800B0102
|
||||
errors.Add ((int)-2146762494);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.NotTimeValid:
|
||||
// WinError.h CERT_E_EXPIRED 0x800B0101
|
||||
description = AlertDescription.CertificateExpired;
|
||||
errors.Add ((int)-2146762495);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.PartialChain:
|
||||
// WinError.h CERT_E_CHAINING 0x800B010A
|
||||
description = AlertDescription.UnknownCA;
|
||||
errors.Add ((int)-2146762486);
|
||||
break;
|
||||
|
||||
case X509ChainStatusFlags.UntrustedRoot:
|
||||
// WinError.h CERT_E_UNTRUSTEDROOT 0x800B0109
|
||||
description = AlertDescription.UnknownCA;
|
||||
errors.Add ((int)-2146762487);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown error
|
||||
description = AlertDescription.CertificateUnknown;
|
||||
errors.Add ((int)verify.Status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
client = new SSCX.X509Certificate (leaf.RawData);
|
||||
certificateErrors = (int[])errors.ToArray (typeof (int));
|
||||
}
|
||||
else
|
||||
{
|
||||
certificateErrors = new int[0];
|
||||
}
|
||||
|
||||
SSCX.X509CertificateCollection certCollection = new SSCX.X509CertificateCollection ();
|
||||
foreach (X509Certificate certificate in certificates) {
|
||||
certCollection.Add (new SSCX.X509Certificate (certificate.RawData));
|
||||
}
|
||||
if (!context.SslStream.RaiseClientCertificateValidation(client, certificateErrors))
|
||||
{
|
||||
throw new TlsException (
|
||||
description,
|
||||
"Invalid certificate received from client.");
|
||||
}
|
||||
|
||||
this.Context.ClientSettings.ClientCertificate = client;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// 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.Security.Cryptography.X509Certificates;
|
||||
|
||||
using System.Security.Cryptography;
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Server
|
||||
{
|
||||
internal class TlsClientCertificateVerify : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientCertificateVerify(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.CertificateVerify, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
int length = this.ReadInt16 ();
|
||||
byte[] signature = this.ReadBytes (length);
|
||||
|
||||
// Verify signature
|
||||
SslHandshakeHash hash = new SslHandshakeHash(context.MasterSecret);
|
||||
hash.TransformFinalBlock(
|
||||
context.HandshakeMessages.ToArray(),
|
||||
0,
|
||||
(int)context.HandshakeMessages.Length);
|
||||
|
||||
if (!hash.VerifySignature(context.ClientSettings.CertificateRSA, signature))
|
||||
{
|
||||
throw new TlsException(AlertDescription.HandshakeFailiure, "Handshake Failure.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
int length = this.ReadInt16 ();
|
||||
byte[] signature = this.ReadBytes (length);
|
||||
|
||||
// Verify signature
|
||||
MD5SHA1 hash = new MD5SHA1();
|
||||
hash.ComputeHash(
|
||||
context.HandshakeMessages.ToArray(),
|
||||
0,
|
||||
(int)context.HandshakeMessages.Length);
|
||||
|
||||
if (!hash.VerifySignature(context.ClientSettings.CertificateRSA, signature))
|
||||
{
|
||||
throw new TlsException (AlertDescription.HandshakeFailiure, "Handshake Failure.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Server
|
||||
{
|
||||
internal class TlsClientFinished : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientFinished(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.Finished, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
// Compute handshake messages hashes
|
||||
HashAlgorithm hash = new SslHandshakeHash(this.Context.MasterSecret);
|
||||
|
||||
TlsStream data = new TlsStream();
|
||||
data.Write(this.Context.HandshakeMessages.ToArray());
|
||||
data.Write((int)0x434C4E54);
|
||||
|
||||
hash.TransformFinalBlock(data.ToArray(), 0, (int)data.Length);
|
||||
|
||||
data.Reset();
|
||||
|
||||
byte[] clientHash = this.ReadBytes((int)Length);
|
||||
byte[] serverHash = hash.Hash;
|
||||
|
||||
// Check client prf against server prf
|
||||
if (!Compare (clientHash, serverHash))
|
||||
{
|
||||
throw new TlsException(AlertDescription.DecryptError, "Decrypt error.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
byte[] clientPRF = this.ReadBytes((int)this.Length);
|
||||
HashAlgorithm hash = new MD5SHA1();
|
||||
|
||||
byte[] data = this.Context.HandshakeMessages.ToArray ();
|
||||
byte[] digest = hash.ComputeHash (data, 0, data.Length);
|
||||
|
||||
byte[] serverPRF = this.Context.Current.Cipher.PRF(
|
||||
this.Context.MasterSecret, "client finished", digest, 12);
|
||||
|
||||
// Check client prf against server prf
|
||||
if (!Compare (clientPRF, serverPRF))
|
||||
{
|
||||
throw new TlsException(AlertDescription.DecryptError, "Decrypt error.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.Security.Cryptography;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Server
|
||||
{
|
||||
internal class TlsClientHello : HandshakeMessage
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private byte[] random;
|
||||
private byte[] sessionId;
|
||||
private short[] cipherSuites;
|
||||
private byte[] compressionMethods;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TlsClientHello(Context context, byte[] buffer)
|
||||
: base(context, HandshakeType.ClientHello, buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
this.selectCipherSuite();
|
||||
this.selectCompressionMethod();
|
||||
|
||||
this.Context.SessionId = this.sessionId;
|
||||
this.Context.ClientRandom = this.random;
|
||||
this.Context.ProtocolNegotiated = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
this.ProcessAsTls1();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
// Client Version
|
||||
this.processProtocol(this.ReadInt16());
|
||||
|
||||
// Random bytes - Unix time + Radom bytes [28]
|
||||
this.random = this.ReadBytes(32);
|
||||
|
||||
// Session id
|
||||
// Send the session ID empty
|
||||
this.sessionId = this.ReadBytes(this.ReadByte());
|
||||
|
||||
// Read Supported Cipher Suites count
|
||||
this.cipherSuites = new short[this.ReadInt16()/2];
|
||||
|
||||
// Read Cipher Suites
|
||||
for (int i = 0; i < this.cipherSuites.Length; i++)
|
||||
{
|
||||
this.cipherSuites[i] = this.ReadInt16();
|
||||
}
|
||||
|
||||
// Compression methods length
|
||||
this.compressionMethods = new byte[this.ReadByte()];
|
||||
|
||||
for (int i = 0; i < this.compressionMethods.Length; i++)
|
||||
{
|
||||
this.compressionMethods[i] = this.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void processProtocol(short protocol)
|
||||
{
|
||||
// a server MUST reply with the hight version supported (`true` for fallback)
|
||||
// so a TLS 1.2 client (like Google Chrome) will be returned that the server uses TLS 1.0
|
||||
// instead of an alert about the protocol
|
||||
SecurityProtocolType clientProtocol = Context.DecodeProtocolCode (protocol, true);
|
||||
|
||||
if ((clientProtocol & this.Context.SecurityProtocolFlags) == clientProtocol ||
|
||||
(this.Context.SecurityProtocolFlags & SecurityProtocolType.Default) == SecurityProtocolType.Default)
|
||||
{
|
||||
this.Context.SecurityProtocol = clientProtocol;
|
||||
this.Context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers (true, clientProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TlsException(AlertDescription.ProtocolVersion, "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)
|
||||
{
|
||||
this.Context.Negotiating.Cipher = this.Context.SupportedCiphers[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.Context.Negotiating.Cipher == null)
|
||||
{
|
||||
throw new TlsException(AlertDescription.InsuficientSecurity, "Insuficient Security");
|
||||
}
|
||||
}
|
||||
|
||||
private void selectCompressionMethod()
|
||||
{
|
||||
this.Context.CompressionMethod = SecurityCompressionType.None;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
// Transport Security Layer (TLS)
|
||||
// Copyright (c) 2003-2004 Carlos Guzman Alvarez
|
||||
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Mono.Security.Protocol.Tls.Handshake.Server
|
||||
{
|
||||
internal class TlsClientKeyExchange : HandshakeMessage
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public TlsClientKeyExchange(Context context, byte[] buffer) :
|
||||
base(context,
|
||||
HandshakeType.ClientKeyExchange,
|
||||
buffer)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void ProcessAsSsl3()
|
||||
{
|
||||
AsymmetricAlgorithm privKey = null;
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
|
||||
// Select the private key information
|
||||
privKey = context.SslStream.RaisePrivateKeySelection(
|
||||
new X509Certificate(context.ServerSettings.Certificates[0].RawData),
|
||||
null);
|
||||
|
||||
if (privKey == null)
|
||||
{
|
||||
throw new TlsException(AlertDescription.UserCancelled, "Server certificate Private Key unavailable.");
|
||||
}
|
||||
|
||||
// Read client premaster secret
|
||||
byte[] clientSecret = this.ReadBytes((int)this.Length);
|
||||
|
||||
// Decrypt premaster secret
|
||||
RSAPKCS1KeyExchangeDeformatter deformatter = new RSAPKCS1KeyExchangeDeformatter(privKey);
|
||||
|
||||
byte[] preMasterSecret = deformatter.DecryptKeyExchange(clientSecret);
|
||||
|
||||
// Create master secret
|
||||
this.Context.Negotiating.Cipher.ComputeMasterSecret(preMasterSecret);
|
||||
|
||||
// Create keys
|
||||
this.Context.Negotiating.Cipher.ComputeKeys ();
|
||||
|
||||
// Initialize Cipher Suite
|
||||
this.Context.Negotiating.Cipher.InitializeCipher ();
|
||||
}
|
||||
|
||||
protected override void ProcessAsTls1()
|
||||
{
|
||||
AsymmetricAlgorithm privKey = null;
|
||||
ServerContext context = (ServerContext)this.Context;
|
||||
|
||||
// Select the private key information
|
||||
// Select the private key information
|
||||
privKey = context.SslStream.RaisePrivateKeySelection(
|
||||
new X509Certificate(context.ServerSettings.Certificates[0].RawData),
|
||||
null);
|
||||
|
||||
if (privKey == null)
|
||||
{
|
||||
throw new TlsException(AlertDescription.UserCancelled, "Server certificate Private Key unavailable.");
|
||||
}
|
||||
|
||||
// Read client premaster secret
|
||||
byte[] clientSecret = this.ReadBytes(this.ReadInt16());
|
||||
|
||||
// Decrypt premaster secret
|
||||
RSAPKCS1KeyExchangeDeformatter deformatter = new RSAPKCS1KeyExchangeDeformatter(privKey);
|
||||
|
||||
byte[] preMasterSecret = deformatter.DecryptKeyExchange(clientSecret);
|
||||
|
||||
// Create master secret
|
||||
this.Context.Negotiating.Cipher.ComputeMasterSecret(preMasterSecret);
|
||||
|
||||
// Create keys
|
||||
this.Context.Negotiating.Cipher.ComputeKeys();
|
||||
|
||||
// Initialize Cipher Suite
|
||||
this.Context.Negotiating.Cipher.InitializeCipher();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user