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.
191 lines
6.9 KiB
191 lines
6.9 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
using System.IO; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls |
|
{ |
|
/// <summary>(D)TLS SRP key exchange (RFC 5054).</summary> |
|
public class TlsSrpKeyExchange |
|
: AbstractTlsKeyExchange |
|
{ |
|
private static int CheckKeyExchange(int keyExchange) |
|
{ |
|
switch (keyExchange) |
|
{ |
|
case KeyExchangeAlgorithm.SRP: |
|
case KeyExchangeAlgorithm.SRP_DSS: |
|
case KeyExchangeAlgorithm.SRP_RSA: |
|
return keyExchange; |
|
default: |
|
throw new ArgumentException("unsupported key exchange algorithm", "keyExchange"); |
|
} |
|
} |
|
|
|
protected TlsSrpIdentity m_srpIdentity; |
|
protected TlsSrpConfigVerifier m_srpConfigVerifier; |
|
protected TlsCertificate m_serverCertificate = null; |
|
protected byte[] m_srpSalt = null; |
|
protected TlsSrp6Client m_srpClient = null; |
|
|
|
protected TlsSrpLoginParameters m_srpLoginParameters; |
|
protected TlsCredentialedSigner m_serverCredentials = null; |
|
protected TlsSrp6Server m_srpServer = null; |
|
|
|
protected BigInteger m_srpPeerCredentials = null; |
|
|
|
public TlsSrpKeyExchange(int keyExchange, TlsSrpIdentity srpIdentity, TlsSrpConfigVerifier srpConfigVerifier) |
|
: base(CheckKeyExchange(keyExchange)) |
|
{ |
|
this.m_srpIdentity = srpIdentity; |
|
this.m_srpConfigVerifier = srpConfigVerifier; |
|
} |
|
|
|
public TlsSrpKeyExchange(int keyExchange, TlsSrpLoginParameters srpLoginParameters) |
|
: base(CheckKeyExchange(keyExchange)) |
|
{ |
|
this.m_srpLoginParameters = srpLoginParameters; |
|
} |
|
|
|
public override void SkipServerCredentials() |
|
{ |
|
if (m_keyExchange != KeyExchangeAlgorithm.SRP) |
|
throw new TlsFatalAlert(AlertDescription.internal_error); |
|
} |
|
|
|
public override void ProcessServerCredentials(TlsCredentials serverCredentials) |
|
{ |
|
if (m_keyExchange == KeyExchangeAlgorithm.SRP) |
|
throw new TlsFatalAlert(AlertDescription.internal_error); |
|
|
|
this.m_serverCredentials = TlsUtilities.RequireSignerCredentials(serverCredentials); |
|
} |
|
|
|
public override void ProcessServerCertificate(Certificate serverCertificate) |
|
{ |
|
if (m_keyExchange == KeyExchangeAlgorithm.SRP) |
|
throw new TlsFatalAlert(AlertDescription.internal_error); |
|
|
|
this.m_serverCertificate = serverCertificate.GetCertificateAt(0); |
|
} |
|
|
|
public override bool RequiresServerKeyExchange |
|
{ |
|
get { return true; } |
|
} |
|
|
|
public override byte[] GenerateServerKeyExchange() |
|
{ |
|
TlsSrpConfig config = m_srpLoginParameters.Config; |
|
|
|
this.m_srpServer = m_context.Crypto.CreateSrp6Server(config, m_srpLoginParameters.Verifier); |
|
|
|
BigInteger B = m_srpServer.GenerateServerCredentials(); |
|
|
|
BigInteger[] ng = config.GetExplicitNG(); |
|
ServerSrpParams srpParams = new ServerSrpParams(ng[0], ng[1], m_srpLoginParameters.Salt, B); |
|
|
|
DigestInputBuffer digestBuffer = new DigestInputBuffer(); |
|
|
|
srpParams.Encode(digestBuffer); |
|
|
|
if (m_serverCredentials != null) |
|
{ |
|
TlsUtilities.GenerateServerKeyExchangeSignature(m_context, m_serverCredentials, null, digestBuffer); |
|
} |
|
|
|
return digestBuffer.ToArray(); |
|
} |
|
|
|
public override void ProcessServerKeyExchange(Stream input) |
|
{ |
|
DigestInputBuffer digestBuffer = null; |
|
Stream teeIn = input; |
|
|
|
if (m_keyExchange != KeyExchangeAlgorithm.SRP) |
|
{ |
|
digestBuffer = new DigestInputBuffer(); |
|
teeIn = new TeeInputStream(input, digestBuffer); |
|
} |
|
|
|
ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn); |
|
|
|
if (digestBuffer != null) |
|
{ |
|
TlsUtilities.VerifyServerKeyExchangeSignature(m_context, input, m_serverCertificate, null, |
|
digestBuffer); |
|
} |
|
|
|
TlsSrpConfig config = new TlsSrpConfig(); |
|
config.SetExplicitNG(new BigInteger[]{ srpParams.N, srpParams.G }); |
|
|
|
if (!m_srpConfigVerifier.Accept(config)) |
|
throw new TlsFatalAlert(AlertDescription.insufficient_security); |
|
|
|
this.m_srpSalt = srpParams.S; |
|
|
|
/* |
|
* RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if |
|
* B % N = 0. |
|
*/ |
|
this.m_srpPeerCredentials = ValidatePublicValue(srpParams.N, srpParams.B); |
|
this.m_srpClient = m_context.Crypto.CreateSrp6Client(config); |
|
} |
|
|
|
public override void ProcessClientCredentials(TlsCredentials clientCredentials) |
|
{ |
|
throw new TlsFatalAlert(AlertDescription.internal_error); |
|
} |
|
|
|
public override void GenerateClientKeyExchange(Stream output) |
|
{ |
|
byte[] identity = m_srpIdentity.GetSrpIdentity(); |
|
byte[] password = m_srpIdentity.GetSrpPassword(); |
|
|
|
BigInteger A = m_srpClient.GenerateClientCredentials(m_srpSalt, identity, password); |
|
TlsSrpUtilities.WriteSrpParameter(A, output); |
|
|
|
m_context.SecurityParameters.m_srpIdentity = Arrays.Clone(identity); |
|
} |
|
|
|
public override void ProcessClientKeyExchange(Stream input) |
|
{ |
|
/* |
|
* RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if |
|
* A % N = 0. |
|
*/ |
|
this.m_srpPeerCredentials = ValidatePublicValue(m_srpLoginParameters.Config.GetExplicitNG()[0], |
|
TlsSrpUtilities.ReadSrpParameter(input)); |
|
|
|
m_context.SecurityParameters.m_srpIdentity = Arrays.Clone(m_srpLoginParameters.Identity); |
|
} |
|
|
|
public override TlsSecret GeneratePreMasterSecret() |
|
{ |
|
BigInteger S = m_srpServer != null |
|
? m_srpServer.CalculateSecret(m_srpPeerCredentials) |
|
: m_srpClient.CalculateSecret(m_srpPeerCredentials); |
|
|
|
// TODO Check if this needs to be a fixed size |
|
return m_context.Crypto.CreateSecret(BigIntegers.AsUnsignedByteArray(S)); |
|
} |
|
|
|
protected static BigInteger ValidatePublicValue(BigInteger N, BigInteger val) |
|
{ |
|
val = val.Mod(N); |
|
|
|
// Check that val % N != 0 |
|
if (val.Equals(BigInteger.Zero)) |
|
throw new TlsFatalAlert(AlertDescription.illegal_parameter); |
|
|
|
return val; |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|