diff options
Diffstat (limited to 'crypto/src/tls/TlsSrpKeyExchange.cs')
-rw-r--r-- | crypto/src/tls/TlsSrpKeyExchange.cs | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/crypto/src/tls/TlsSrpKeyExchange.cs b/crypto/src/tls/TlsSrpKeyExchange.cs new file mode 100644 index 000000000..835523e36 --- /dev/null +++ b/crypto/src/tls/TlsSrpKeyExchange.cs @@ -0,0 +1,186 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Tls.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace 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, 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, 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; + } + } +} |