init commit
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Tls;
|
||||
|
||||
public class TlsClientProtocol : TlsProtocol
|
||||
{
|
||||
protected TlsClient mTlsClient = null;
|
||||
|
||||
internal TlsClientContextImpl mTlsClientContext = null;
|
||||
|
||||
protected byte[] mSelectedSessionID = null;
|
||||
|
||||
protected TlsKeyExchange mKeyExchange = null;
|
||||
|
||||
protected TlsAuthentication mAuthentication = null;
|
||||
|
||||
protected CertificateStatus mCertificateStatus = null;
|
||||
|
||||
protected CertificateRequest mCertificateRequest = null;
|
||||
|
||||
protected override TlsContext Context => mTlsClientContext;
|
||||
|
||||
internal override AbstractTlsContext ContextAdmin => mTlsClientContext;
|
||||
|
||||
protected override TlsPeer Peer => mTlsClient;
|
||||
|
||||
public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
|
||||
: base(stream, secureRandom)
|
||||
{
|
||||
}
|
||||
|
||||
public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
|
||||
: base(input, output, secureRandom)
|
||||
{
|
||||
}
|
||||
|
||||
public TlsClientProtocol(SecureRandom secureRandom)
|
||||
: base(secureRandom)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Connect(TlsClient tlsClient)
|
||||
{
|
||||
if (tlsClient == null)
|
||||
{
|
||||
throw new ArgumentNullException("tlsClient");
|
||||
}
|
||||
if (mTlsClient != null)
|
||||
{
|
||||
throw new InvalidOperationException("'Connect' can only be called once");
|
||||
}
|
||||
mTlsClient = tlsClient;
|
||||
mSecurityParameters = new SecurityParameters();
|
||||
mSecurityParameters.entity = 1;
|
||||
mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
|
||||
mSecurityParameters.clientRandom = TlsProtocol.CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(), mTlsClientContext.NonceRandomGenerator);
|
||||
mTlsClient.Init(mTlsClientContext);
|
||||
mRecordStream.Init(mTlsClientContext);
|
||||
TlsSession sessionToResume = tlsClient.GetSessionToResume();
|
||||
if (sessionToResume != null && sessionToResume.IsResumable)
|
||||
{
|
||||
SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
|
||||
if (sessionParameters != null && sessionParameters.IsExtendedMasterSecret)
|
||||
{
|
||||
mTlsSession = sessionToResume;
|
||||
mSessionParameters = sessionParameters;
|
||||
}
|
||||
}
|
||||
SendClientHelloMessage();
|
||||
mConnectionState = 1;
|
||||
BlockForHandshake();
|
||||
}
|
||||
|
||||
protected override void CleanupHandshake()
|
||||
{
|
||||
base.CleanupHandshake();
|
||||
mSelectedSessionID = null;
|
||||
mKeyExchange = null;
|
||||
mAuthentication = null;
|
||||
mCertificateStatus = null;
|
||||
mCertificateRequest = null;
|
||||
}
|
||||
|
||||
protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
|
||||
{
|
||||
if (mResumedSession)
|
||||
{
|
||||
if (type != 20 || mConnectionState != 2)
|
||||
{
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
ProcessFinishedMessage(buf);
|
||||
mConnectionState = 15;
|
||||
SendChangeCipherSpecMessage();
|
||||
SendFinishedMessage();
|
||||
mConnectionState = 13;
|
||||
CompleteHandshake();
|
||||
return;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case 11:
|
||||
switch (mConnectionState)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
if (mConnectionState == 2)
|
||||
{
|
||||
HandleSupplementalData(null);
|
||||
}
|
||||
mPeerCertificate = Certificate.Parse(buf);
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
if (mPeerCertificate == null || mPeerCertificate.IsEmpty)
|
||||
{
|
||||
mAllowCertificateStatus = false;
|
||||
}
|
||||
mKeyExchange.ProcessServerCertificate(mPeerCertificate);
|
||||
mAuthentication = mTlsClient.GetAuthentication();
|
||||
mAuthentication.NotifyServerCertificate(mPeerCertificate);
|
||||
mConnectionState = 4;
|
||||
break;
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
break;
|
||||
case 22:
|
||||
{
|
||||
short num = mConnectionState;
|
||||
if (num == 4)
|
||||
{
|
||||
if (!mAllowCertificateStatus)
|
||||
{
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
mCertificateStatus = CertificateStatus.Parse(buf);
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
mConnectionState = 5;
|
||||
break;
|
||||
}
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
case 20:
|
||||
switch (mConnectionState)
|
||||
{
|
||||
case 13:
|
||||
case 14:
|
||||
if (mConnectionState == 13 && mExpectSessionTicket)
|
||||
{
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
ProcessFinishedMessage(buf);
|
||||
mConnectionState = 15;
|
||||
CompleteHandshake();
|
||||
break;
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
short num = mConnectionState;
|
||||
if (num == 1)
|
||||
{
|
||||
ReceiveServerHelloMessage(buf);
|
||||
mConnectionState = 2;
|
||||
mRecordStream.NotifyHelloComplete();
|
||||
ApplyMaxFragmentLengthExtension();
|
||||
if (mResumedSession)
|
||||
{
|
||||
mSecurityParameters.masterSecret = Arrays.Clone(mSessionParameters.MasterSecret);
|
||||
mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
|
||||
break;
|
||||
}
|
||||
InvalidateSession();
|
||||
if (mSelectedSessionID.Length > 0)
|
||||
{
|
||||
mTlsSession = new TlsSessionImpl(mSelectedSessionID, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
case 23:
|
||||
{
|
||||
short num = mConnectionState;
|
||||
if (num == 2)
|
||||
{
|
||||
HandleSupplementalData(TlsProtocol.ReadSupplementalDataMessage(buf));
|
||||
break;
|
||||
}
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
case 14:
|
||||
switch (mConnectionState)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
if (mConnectionState < 3)
|
||||
{
|
||||
HandleSupplementalData(null);
|
||||
}
|
||||
if (mConnectionState < 4)
|
||||
{
|
||||
mKeyExchange.SkipServerCredentials();
|
||||
mAuthentication = null;
|
||||
}
|
||||
if (mConnectionState < 6)
|
||||
{
|
||||
mKeyExchange.SkipServerKeyExchange();
|
||||
}
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
mConnectionState = 8;
|
||||
mRecordStream.HandshakeHash.SealHashAlgorithms();
|
||||
IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
|
||||
if (clientSupplementalData != null)
|
||||
{
|
||||
SendSupplementalDataMessage(clientSupplementalData);
|
||||
}
|
||||
mConnectionState = 9;
|
||||
TlsCredentials tlsCredentials = null;
|
||||
if (mCertificateRequest == null)
|
||||
{
|
||||
mKeyExchange.SkipClientCredentials();
|
||||
}
|
||||
else
|
||||
{
|
||||
tlsCredentials = mAuthentication.GetClientCredentials(mCertificateRequest);
|
||||
if (tlsCredentials == null)
|
||||
{
|
||||
mKeyExchange.SkipClientCredentials();
|
||||
SendCertificateMessage(Certificate.EmptyChain);
|
||||
}
|
||||
else
|
||||
{
|
||||
mKeyExchange.ProcessClientCredentials(tlsCredentials);
|
||||
SendCertificateMessage(tlsCredentials.Certificate);
|
||||
}
|
||||
}
|
||||
mConnectionState = 10;
|
||||
SendClientKeyExchangeMessage();
|
||||
mConnectionState = 11;
|
||||
if (TlsUtilities.IsSsl(Context))
|
||||
{
|
||||
TlsProtocol.EstablishMasterSecret(Context, mKeyExchange);
|
||||
}
|
||||
TlsHandshakeHash tlsHandshakeHash = mRecordStream.PrepareToFinish();
|
||||
mSecurityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(Context, tlsHandshakeHash, null);
|
||||
if (!TlsUtilities.IsSsl(Context))
|
||||
{
|
||||
TlsProtocol.EstablishMasterSecret(Context, mKeyExchange);
|
||||
}
|
||||
mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
|
||||
if (tlsCredentials != null && tlsCredentials is TlsSignerCredentials)
|
||||
{
|
||||
TlsSignerCredentials tlsSignerCredentials = (TlsSignerCredentials)tlsCredentials;
|
||||
SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(Context, tlsSignerCredentials);
|
||||
byte[] hash = ((signatureAndHashAlgorithm != null) ? tlsHandshakeHash.GetFinalHash(signatureAndHashAlgorithm.Hash) : mSecurityParameters.SessionHash);
|
||||
byte[] signature = tlsSignerCredentials.GenerateCertificateSignature(hash);
|
||||
DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
|
||||
SendCertificateVerifyMessage(certificateVerify);
|
||||
mConnectionState = 12;
|
||||
}
|
||||
SendChangeCipherSpecMessage();
|
||||
SendFinishedMessage();
|
||||
mConnectionState = 13;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
switch (mConnectionState)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
if (mConnectionState < 3)
|
||||
{
|
||||
HandleSupplementalData(null);
|
||||
}
|
||||
if (mConnectionState < 4)
|
||||
{
|
||||
mKeyExchange.SkipServerCredentials();
|
||||
mAuthentication = null;
|
||||
}
|
||||
mKeyExchange.ProcessServerKeyExchange(buf);
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
mConnectionState = 6;
|
||||
break;
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (mConnectionState)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
if (mConnectionState != 6)
|
||||
{
|
||||
mKeyExchange.SkipServerKeyExchange();
|
||||
}
|
||||
if (mAuthentication == null)
|
||||
{
|
||||
throw new TlsFatalAlert(40);
|
||||
}
|
||||
mCertificateRequest = CertificateRequest.Parse(Context, buf);
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
|
||||
TlsUtilities.TrackHashAlgorithms(mRecordStream.HandshakeHash, mCertificateRequest.SupportedSignatureAlgorithms);
|
||||
mConnectionState = 7;
|
||||
break;
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
short num = mConnectionState;
|
||||
if (num == 13)
|
||||
{
|
||||
if (!mExpectSessionTicket)
|
||||
{
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
InvalidateSession();
|
||||
ReceiveNewSessionTicketMessage(buf);
|
||||
mConnectionState = 14;
|
||||
break;
|
||||
}
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
case 0:
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
if (mConnectionState == 16)
|
||||
{
|
||||
RefuseRenegotiation();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new TlsFatalAlert(10);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void HandleSupplementalData(IList serverSupplementalData)
|
||||
{
|
||||
mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
|
||||
mConnectionState = 3;
|
||||
mKeyExchange = mTlsClient.GetKeyExchange();
|
||||
mKeyExchange.Init(Context);
|
||||
}
|
||||
|
||||
protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
|
||||
{
|
||||
NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
|
||||
TlsProtocol.AssertEmpty(buf);
|
||||
mTlsClient.NotifyNewSessionTicket(newSessionTicket);
|
||||
}
|
||||
|
||||
protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
|
||||
{
|
||||
ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(buf);
|
||||
if (protocolVersion.IsDtls)
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
if (!protocolVersion.Equals(mRecordStream.ReadVersion))
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
ProtocolVersion clientVersion = Context.ClientVersion;
|
||||
if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion))
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
mRecordStream.SetWriteVersion(protocolVersion);
|
||||
ContextAdmin.SetServerVersion(protocolVersion);
|
||||
mTlsClient.NotifyServerVersion(protocolVersion);
|
||||
mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
|
||||
mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
|
||||
if (mSelectedSessionID.Length > 32)
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
mTlsClient.NotifySessionID(mSelectedSessionID);
|
||||
mResumedSession = mSelectedSessionID.Length > 0 && mTlsSession != null && Arrays.AreEqual(mSelectedSessionID, mTlsSession.SessionID);
|
||||
int num = TlsUtilities.ReadUint16(buf);
|
||||
if (!Arrays.Contains(mOfferedCipherSuites, num) || num == 0 || CipherSuite.IsScsv(num) || !TlsUtilities.IsValidCipherSuiteForVersion(num, Context.ServerVersion))
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
mTlsClient.NotifySelectedCipherSuite(num);
|
||||
byte b = TlsUtilities.ReadUint8(buf);
|
||||
if (!Arrays.Contains(mOfferedCompressionMethods, b))
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
mTlsClient.NotifySelectedCompressionMethod(b);
|
||||
mServerExtensions = TlsProtocol.ReadExtensions(buf);
|
||||
mSecurityParameters.extendedMasterSecret = !TlsUtilities.IsSsl(mTlsClientContext) && TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
|
||||
if (!mSecurityParameters.IsExtendedMasterSecret && (mResumedSession || mTlsClient.RequiresExtendedMasterSecret()))
|
||||
{
|
||||
throw new TlsFatalAlert(40);
|
||||
}
|
||||
if (mServerExtensions != null)
|
||||
{
|
||||
foreach (object key in mServerExtensions.Keys)
|
||||
{
|
||||
int num2 = (int)key;
|
||||
if (num2 != 65281)
|
||||
{
|
||||
if (TlsUtilities.GetExtensionData(mClientExtensions, num2) == null)
|
||||
{
|
||||
throw new TlsFatalAlert(110);
|
||||
}
|
||||
_ = mResumedSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281);
|
||||
if (extensionData != null)
|
||||
{
|
||||
mSecureRenegotiation = true;
|
||||
if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
|
||||
{
|
||||
throw new TlsFatalAlert(40);
|
||||
}
|
||||
}
|
||||
mTlsClient.NotifySecureRenegotiation(mSecureRenegotiation);
|
||||
IDictionary dictionary = mClientExtensions;
|
||||
IDictionary dictionary2 = mServerExtensions;
|
||||
if (mResumedSession)
|
||||
{
|
||||
if (num != mSessionParameters.CipherSuite || b != mSessionParameters.CompressionAlgorithm)
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
dictionary = null;
|
||||
dictionary2 = mSessionParameters.ReadServerExtensions();
|
||||
}
|
||||
mSecurityParameters.cipherSuite = num;
|
||||
mSecurityParameters.compressionAlgorithm = b;
|
||||
if (dictionary2 != null && dictionary2.Count > 0)
|
||||
{
|
||||
bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(dictionary2);
|
||||
if (flag && !TlsUtilities.IsBlockCipherSuite(num))
|
||||
{
|
||||
throw new TlsFatalAlert(47);
|
||||
}
|
||||
mSecurityParameters.encryptThenMac = flag;
|
||||
mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(dictionary, dictionary2, 47);
|
||||
mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(dictionary2);
|
||||
mAllowCertificateStatus = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 5, 47);
|
||||
mExpectSessionTicket = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 35, 47);
|
||||
}
|
||||
if (dictionary != null)
|
||||
{
|
||||
mTlsClient.ProcessServerExtensions(dictionary2);
|
||||
}
|
||||
mSecurityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
|
||||
mSecurityParameters.verifyDataLength = 12;
|
||||
}
|
||||
|
||||
protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
|
||||
{
|
||||
HandshakeMessage handshakeMessage = new HandshakeMessage(15);
|
||||
certificateVerify.Encode(handshakeMessage);
|
||||
handshakeMessage.WriteToRecordStream(this);
|
||||
}
|
||||
|
||||
protected virtual void SendClientHelloMessage()
|
||||
{
|
||||
mRecordStream.SetWriteVersion(mTlsClient.ClientHelloRecordLayerVersion);
|
||||
ProtocolVersion clientVersion = mTlsClient.ClientVersion;
|
||||
if (clientVersion.IsDtls)
|
||||
{
|
||||
throw new TlsFatalAlert(80);
|
||||
}
|
||||
ContextAdmin.SetClientVersion(clientVersion);
|
||||
byte[] array = TlsUtilities.EmptyBytes;
|
||||
if (mTlsSession != null)
|
||||
{
|
||||
array = mTlsSession.SessionID;
|
||||
if (array == null || array.Length > 32)
|
||||
{
|
||||
array = TlsUtilities.EmptyBytes;
|
||||
}
|
||||
}
|
||||
bool isFallback = mTlsClient.IsFallback;
|
||||
mOfferedCipherSuites = mTlsClient.GetCipherSuites();
|
||||
mOfferedCompressionMethods = mTlsClient.GetCompressionMethods();
|
||||
if (array.Length > 0 && mSessionParameters != null && (!mSessionParameters.IsExtendedMasterSecret || !Arrays.Contains(mOfferedCipherSuites, mSessionParameters.CipherSuite) || !Arrays.Contains(mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm)))
|
||||
{
|
||||
array = TlsUtilities.EmptyBytes;
|
||||
}
|
||||
mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsClient.GetClientExtensions());
|
||||
if (!clientVersion.IsSsl)
|
||||
{
|
||||
TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mClientExtensions);
|
||||
}
|
||||
HandshakeMessage handshakeMessage = new HandshakeMessage(1);
|
||||
TlsUtilities.WriteVersion(clientVersion, handshakeMessage);
|
||||
handshakeMessage.Write(mSecurityParameters.ClientRandom);
|
||||
TlsUtilities.WriteOpaque8(array, handshakeMessage);
|
||||
byte[] extensionData = TlsUtilities.GetExtensionData(mClientExtensions, 65281);
|
||||
bool flag = null == extensionData;
|
||||
bool flag2 = !Arrays.Contains(mOfferedCipherSuites, 255);
|
||||
if (flag && flag2)
|
||||
{
|
||||
mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, 255);
|
||||
}
|
||||
if (isFallback && !Arrays.Contains(mOfferedCipherSuites, 22016))
|
||||
{
|
||||
mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, 22016);
|
||||
}
|
||||
TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, handshakeMessage);
|
||||
TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, handshakeMessage);
|
||||
TlsProtocol.WriteExtensions(handshakeMessage, mClientExtensions);
|
||||
handshakeMessage.WriteToRecordStream(this);
|
||||
}
|
||||
|
||||
protected virtual void SendClientKeyExchangeMessage()
|
||||
{
|
||||
HandshakeMessage handshakeMessage = new HandshakeMessage(16);
|
||||
mKeyExchange.GenerateClientKeyExchange(handshakeMessage);
|
||||
handshakeMessage.WriteToRecordStream(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user