123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Collections;
- using System.IO;
- using Org.BouncyCastle.Asn1.X509;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Security;
- namespace Org.BouncyCastle.Crypto.Tls
- {
- /// <summary>(D)TLS ECDH key exchange (see RFC 4492).</summary>
- public class TlsECDHKeyExchange
- : AbstractTlsKeyExchange
- {
- protected TlsSigner mTlsSigner;
- protected int[] mNamedCurves;
- protected byte[] mClientECPointFormats, mServerECPointFormats;
- protected AsymmetricKeyParameter mServerPublicKey;
- protected TlsAgreementCredentials mAgreementCredentials;
- protected ECPrivateKeyParameters mECAgreePrivateKey;
- protected ECPublicKeyParameters mECAgreePublicKey;
- public TlsECDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
- byte[] clientECPointFormats, byte[] serverECPointFormats)
- : base(keyExchange, supportedSignatureAlgorithms)
- {
- switch (keyExchange)
- {
- case KeyExchangeAlgorithm.ECDHE_RSA:
- this.mTlsSigner = new TlsRsaSigner();
- break;
- case KeyExchangeAlgorithm.ECDHE_ECDSA:
- this.mTlsSigner = new TlsECDsaSigner();
- break;
- case KeyExchangeAlgorithm.ECDH_anon:
- case KeyExchangeAlgorithm.ECDH_RSA:
- case KeyExchangeAlgorithm.ECDH_ECDSA:
- this.mTlsSigner = null;
- break;
- default:
- throw new InvalidOperationException("unsupported key exchange algorithm");
- }
- this.mNamedCurves = namedCurves;
- this.mClientECPointFormats = clientECPointFormats;
- this.mServerECPointFormats = serverECPointFormats;
- }
- public override void Init(TlsContext context)
- {
- base.Init(context);
- if (this.mTlsSigner != null)
- {
- this.mTlsSigner.Init(context);
- }
- }
- public override void SkipServerCredentials()
- {
- if (mKeyExchange != KeyExchangeAlgorithm.ECDH_anon)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- public override void ProcessServerCertificate(Certificate serverCertificate)
- {
- if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- if (serverCertificate.IsEmpty)
- throw new TlsFatalAlert(AlertDescription.bad_certificate);
- X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
- try
- {
- this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
- }
- catch (Exception e)
- {
- throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
- }
- if (mTlsSigner == null)
- {
- try
- {
- this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters) this.mServerPublicKey);
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
- }
- else
- {
- if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
- }
- base.ProcessServerCertificate(serverCertificate);
- }
- public override bool RequiresServerKeyExchange
- {
- get
- {
- switch (mKeyExchange)
- {
- case KeyExchangeAlgorithm.ECDH_anon:
- case KeyExchangeAlgorithm.ECDHE_ECDSA:
- case KeyExchangeAlgorithm.ECDHE_RSA:
- return true;
- default:
- return false;
- }
- }
- }
- public override byte[] GenerateServerKeyExchange()
- {
- if (!RequiresServerKeyExchange)
- return null;
- // ECDH_anon is handled here, ECDHE_* in a subclass
- MemoryStream buf = new MemoryStream();
- this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
- mClientECPointFormats, buf);
- return buf.ToArray();
- }
- public override void ProcessServerKeyExchange(Stream input)
- {
- if (!RequiresServerKeyExchange)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- // ECDH_anon is handled here, ECDHE_* in a subclass
- ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
- byte[] point = TlsUtilities.ReadOpaque8(input);
- 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:
- case ClientCertificateType.rsa_fixed_ecdh:
- case ClientCertificateType.ecdsa_fixed_ecdh:
- break;
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- }
- }
- public override void ProcessClientCredentials(TlsCredentials clientCredentials)
- {
- if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
- throw new TlsFatalAlert(AlertDescription.internal_error);
- if (clientCredentials is TlsAgreementCredentials)
- {
- // TODO Validate client cert has matching parameters (see 'TlsEccUtilities.AreOnSameCurve')?
- this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
- }
- else if (clientCredentials is TlsSignerCredentials)
- {
- // OK
- }
- else
- {
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
- public override void GenerateClientKeyExchange(Stream output)
- {
- if (mAgreementCredentials == null)
- {
- this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
- mServerECPointFormats, mECAgreePublicKey.Parameters, output);
- }
- }
- public override void ProcessClientCertificate(Certificate clientCertificate)
- {
- if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- // TODO Extract the public key
- // TODO If the certificate is 'fixed', take the public key as mECAgreeClientPublicKey
- }
- public override void ProcessClientKeyExchange(Stream input)
- {
- if (mECAgreePublicKey != null)
- {
- // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
- return;
- }
- byte[] point = TlsUtilities.ReadOpaque8(input);
- ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
- this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
- mServerECPointFormats, curve_params, point));
- }
- public override byte[] GeneratePremasterSecret()
- {
- if (mAgreementCredentials != null)
- {
- return mAgreementCredentials.GenerateAgreement(mECAgreePublicKey);
- }
- if (mECAgreePrivateKey != null)
- {
- return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
- }
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- }
- }
- #endif
|