You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
7.2 KiB
250 lines
7.2 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.IO;
|
||
|
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls
|
||
|
{
|
||
|
/// <summary>Buffers input until the hash algorithm is determined.</summary>
|
||
|
internal sealed class DeferredHash
|
||
|
: TlsHandshakeHash
|
||
|
{
|
||
|
private const int BufferingHashLimit = 4;
|
||
|
|
||
|
private readonly TlsContext m_context;
|
||
|
|
||
|
private DigestInputBuffer m_buf;
|
||
|
private readonly IDictionary m_hashes;
|
||
|
private bool m_forceBuffering;
|
||
|
private bool m_sealed;
|
||
|
|
||
|
internal DeferredHash(TlsContext context)
|
||
|
{
|
||
|
this.m_context = context;
|
||
|
this.m_buf = new DigestInputBuffer();
|
||
|
this.m_hashes = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
|
||
|
this.m_forceBuffering = false;
|
||
|
this.m_sealed = false;
|
||
|
}
|
||
|
|
||
|
private DeferredHash(TlsContext context, IDictionary hashes)
|
||
|
{
|
||
|
this.m_context = context;
|
||
|
this.m_buf = null;
|
||
|
this.m_hashes = hashes;
|
||
|
this.m_forceBuffering = false;
|
||
|
this.m_sealed = true;
|
||
|
}
|
||
|
|
||
|
/// <exception cref="IOException"/>
|
||
|
public void CopyBufferTo(Stream output)
|
||
|
{
|
||
|
if (m_buf == null)
|
||
|
{
|
||
|
// If you see this, you need to call forceBuffering() before SealHashAlgorithms()
|
||
|
throw new InvalidOperationException("Not buffering");
|
||
|
}
|
||
|
|
||
|
m_buf.CopyTo(output);
|
||
|
}
|
||
|
|
||
|
public void ForceBuffering()
|
||
|
{
|
||
|
if (m_sealed)
|
||
|
throw new InvalidOperationException("Too late to force buffering");
|
||
|
|
||
|
this.m_forceBuffering = true;
|
||
|
}
|
||
|
|
||
|
public void NotifyPrfDetermined()
|
||
|
{
|
||
|
SecurityParameters securityParameters = m_context.SecurityParameters;
|
||
|
|
||
|
switch (securityParameters.PrfAlgorithm)
|
||
|
{
|
||
|
case PrfAlgorithm.ssl_prf_legacy:
|
||
|
case PrfAlgorithm.tls_prf_legacy:
|
||
|
{
|
||
|
CheckTrackingHash(CryptoHashAlgorithm.md5);
|
||
|
CheckTrackingHash(CryptoHashAlgorithm.sha1);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
CheckTrackingHash(securityParameters.PrfCryptoHashAlgorithm);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void TrackHashAlgorithm(int cryptoHashAlgorithm)
|
||
|
{
|
||
|
if (m_sealed)
|
||
|
throw new InvalidOperationException("Too late to track more hash algorithms");
|
||
|
|
||
|
CheckTrackingHash(cryptoHashAlgorithm);
|
||
|
}
|
||
|
|
||
|
public void SealHashAlgorithms()
|
||
|
{
|
||
|
if (m_sealed)
|
||
|
throw new InvalidOperationException("Already sealed");
|
||
|
|
||
|
this.m_sealed = true;
|
||
|
CheckStopBuffering();
|
||
|
}
|
||
|
|
||
|
public TlsHandshakeHash StopTracking()
|
||
|
{
|
||
|
SecurityParameters securityParameters = m_context.SecurityParameters;
|
||
|
|
||
|
IDictionary newHashes = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
|
||
|
switch (securityParameters.PrfAlgorithm)
|
||
|
{
|
||
|
case PrfAlgorithm.ssl_prf_legacy:
|
||
|
case PrfAlgorithm.tls_prf_legacy:
|
||
|
{
|
||
|
CloneHash(newHashes, HashAlgorithm.md5);
|
||
|
CloneHash(newHashes, HashAlgorithm.sha1);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
CloneHash(newHashes, securityParameters.PrfCryptoHashAlgorithm);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return new DeferredHash(m_context, newHashes);
|
||
|
}
|
||
|
|
||
|
public TlsHash ForkPrfHash()
|
||
|
{
|
||
|
CheckStopBuffering();
|
||
|
|
||
|
SecurityParameters securityParameters = m_context.SecurityParameters;
|
||
|
|
||
|
TlsHash prfHash;
|
||
|
switch (securityParameters.PrfAlgorithm)
|
||
|
{
|
||
|
case PrfAlgorithm.ssl_prf_legacy:
|
||
|
case PrfAlgorithm.tls_prf_legacy:
|
||
|
{
|
||
|
prfHash = new CombinedHash(m_context, CloneHash(HashAlgorithm.md5), CloneHash(HashAlgorithm.sha1));
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
prfHash = CloneHash(securityParameters.PrfCryptoHashAlgorithm);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_buf != null)
|
||
|
{
|
||
|
m_buf.UpdateDigest(prfHash);
|
||
|
}
|
||
|
|
||
|
return prfHash;
|
||
|
}
|
||
|
|
||
|
public byte[] GetFinalHash(int cryptoHashAlgorithm)
|
||
|
{
|
||
|
TlsHash d = (TlsHash)m_hashes[cryptoHashAlgorithm];
|
||
|
if (d == null)
|
||
|
throw new InvalidOperationException("CryptoHashAlgorithm." + cryptoHashAlgorithm
|
||
|
+ " is not being tracked");
|
||
|
|
||
|
CheckStopBuffering();
|
||
|
|
||
|
d = d.CloneHash();
|
||
|
if (m_buf != null)
|
||
|
{
|
||
|
m_buf.UpdateDigest(d);
|
||
|
}
|
||
|
|
||
|
return d.CalculateHash();
|
||
|
}
|
||
|
|
||
|
public void Update(byte[] input, int inOff, int len)
|
||
|
{
|
||
|
if (m_buf != null)
|
||
|
{
|
||
|
m_buf.Write(input, inOff, len);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
foreach (TlsHash hash in m_hashes.Values)
|
||
|
{
|
||
|
hash.Update(input, inOff, len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public byte[] CalculateHash()
|
||
|
{
|
||
|
throw new InvalidOperationException("Use 'ForkPrfHash' to get a definite hash");
|
||
|
}
|
||
|
|
||
|
public TlsHash CloneHash()
|
||
|
{
|
||
|
throw new InvalidOperationException("attempt to clone a DeferredHash");
|
||
|
}
|
||
|
|
||
|
public void Reset()
|
||
|
{
|
||
|
if (m_buf != null)
|
||
|
{
|
||
|
m_buf.SetLength(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
foreach (TlsHash hash in m_hashes.Values)
|
||
|
{
|
||
|
hash.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CheckStopBuffering()
|
||
|
{
|
||
|
if (!m_forceBuffering && m_sealed && m_buf != null && m_hashes.Count <= BufferingHashLimit)
|
||
|
{
|
||
|
foreach (TlsHash hash in m_hashes.Values)
|
||
|
{
|
||
|
m_buf.UpdateDigest(hash);
|
||
|
}
|
||
|
|
||
|
this.m_buf = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void CheckTrackingHash(int cryptoHashAlgorithm)
|
||
|
{
|
||
|
if (!m_hashes.Contains(cryptoHashAlgorithm))
|
||
|
{
|
||
|
TlsHash hash = m_context.Crypto.CreateHash(cryptoHashAlgorithm);
|
||
|
m_hashes[cryptoHashAlgorithm] = hash;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private TlsHash CloneHash(int cryptoHashAlgorithm)
|
||
|
{
|
||
|
return ((TlsHash)m_hashes[cryptoHashAlgorithm]).CloneHash();
|
||
|
}
|
||
|
|
||
|
private void CloneHash(IDictionary newHashes, int cryptoHashAlgorithm)
|
||
|
{
|
||
|
TlsHash hash = CloneHash(cryptoHashAlgorithm);
|
||
|
if (m_buf != null)
|
||
|
{
|
||
|
m_buf.UpdateDigest(hash);
|
||
|
}
|
||
|
newHashes[cryptoHashAlgorithm] = hash;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|