#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) using System; using System.Collections; using System.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Crypto.Tls { /// (D)TLS ECDHE key exchange (see RFC 4492). public class TlsECDheKeyExchange : TlsECDHKeyExchange { protected TlsSignerCredentials mServerCredentials = null; public TlsECDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves, byte[] clientECPointFormats, byte[] serverECPointFormats) : base(keyExchange, supportedSignatureAlgorithms, namedCurves, clientECPointFormats, serverECPointFormats) { } public override void ProcessServerCredentials(TlsCredentials serverCredentials) { if (!(serverCredentials is TlsSignerCredentials)) throw new TlsFatalAlert(AlertDescription.internal_error); ProcessServerCertificate(serverCredentials.Certificate); this.mServerCredentials = (TlsSignerCredentials)serverCredentials; } public override byte[] GenerateServerKeyExchange() { DigestInputBuffer buf = new DigestInputBuffer(); this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves, mClientECPointFormats, buf); /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( mContext, mServerCredentials); IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm); SecurityParameters securityParameters = mContext.SecurityParameters; d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); buf.UpdateDigest(d); byte[] hash = DigestUtilities.DoFinal(d); byte[] signature = mServerCredentials.GenerateCertificateSignature(hash); DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature); signed_params.Encode(buf); return buf.ToArray(); } public override void ProcessServerKeyExchange(Stream input) { SecurityParameters securityParameters = mContext.SecurityParameters; SignerInputBuffer buf = new SignerInputBuffer(); Stream teeIn = new TeeInputStream(input, buf); ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, teeIn); byte[] point = TlsUtilities.ReadOpaque8(teeIn); DigitallySigned signed_params = ParseSignature(input); ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters); buf.UpdateSigner(signer); if (!signer.VerifySignature(signed_params.Signature)) throw new TlsFatalAlert(AlertDescription.decrypt_error); this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey( mClientECPointFormats, curve_params, point)); } public override void ValidateCertificateRequest(CertificateRequest certificateRequest) { /* * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because * the use of a long-term ECDH client key would jeopardize the forward secrecy property of * these algorithms. */ byte[] types = certificateRequest.CertificateTypes; for (int i = 0; i < types.Length; ++i) { switch (types[i]) { case ClientCertificateType.rsa_sign: case ClientCertificateType.dss_sign: case ClientCertificateType.ecdsa_sign: break; default: throw new TlsFatalAlert(AlertDescription.illegal_parameter); } } } public override void ProcessClientCredentials(TlsCredentials clientCredentials) { if (clientCredentials is TlsSignerCredentials) { // OK } else { throw new TlsFatalAlert(AlertDescription.internal_error); } } protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm, SecurityParameters securityParameters) { ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey); signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); return signer; } } } #endif