2025-05-07 11:20:40 +08:00

254 lines
9.0 KiB
C#

#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.Asn1.X509;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
{
/// <summary>(D)TLS DH key exchange.</summary>
public class TlsDHKeyExchange
: AbstractTlsKeyExchange
{
protected TlsSigner mTlsSigner;
protected TlsDHVerifier mDHVerifier;
protected DHParameters mDHParameters;
protected AsymmetricKeyParameter mServerPublicKey;
protected TlsAgreementCredentials mAgreementCredentials;
protected DHPrivateKeyParameters mDHAgreePrivateKey;
protected DHPublicKeyParameters mDHAgreePublicKey;
[Obsolete("Use constructor that takes a TlsDHVerifier")]
public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
: this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsDHVerifier(), dhParameters)
{
}
public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters)
: base(keyExchange, supportedSignatureAlgorithms)
{
switch (keyExchange)
{
case KeyExchangeAlgorithm.DH_anon:
case KeyExchangeAlgorithm.DH_RSA:
case KeyExchangeAlgorithm.DH_DSS:
this.mTlsSigner = null;
break;
case KeyExchangeAlgorithm.DHE_RSA:
this.mTlsSigner = new TlsRsaSigner();
break;
case KeyExchangeAlgorithm.DHE_DSS:
this.mTlsSigner = new TlsDssSigner();
break;
default:
throw new InvalidOperationException("unsupported key exchange algorithm");
}
this.mDHVerifier = dhVerifier;
this.mDHParameters = dhParameters;
}
public override void Init(TlsContext context)
{
base.Init(context);
if (this.mTlsSigner != null)
{
this.mTlsSigner.Init(context);
}
}
public override void SkipServerCredentials()
{
if (mKeyExchange != KeyExchangeAlgorithm.DH_anon)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
public override void ProcessServerCertificate(Certificate serverCertificate)
{
if (mKeyExchange == KeyExchangeAlgorithm.DH_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.mDHAgreePublicKey = (DHPublicKeyParameters)this.mServerPublicKey;
this.mDHParameters = mDHAgreePublicKey.Parameters;
}
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.DH_anon:
case KeyExchangeAlgorithm.DHE_DSS:
case KeyExchangeAlgorithm.DHE_RSA:
return true;
default:
return false;
}
}
}
public override byte[] GenerateServerKeyExchange()
{
if (!RequiresServerKeyExchange)
return null;
// DH_anon is handled here, DHE_* in a subclass
MemoryStream buf = new MemoryStream();
this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
this.mDHParameters, buf);
return buf.ToArray();
}
public override void ProcessServerKeyExchange(Stream input)
{
if (!RequiresServerKeyExchange)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
// DH_anon is handled here, DHE_* in a subclass
this.mDHParameters = TlsDHUtilities.ReceiveDHParameters(mDHVerifier, input);
this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters);
}
public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
{
if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
throw new TlsFatalAlert(AlertDescription.handshake_failure);
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.rsa_fixed_dh:
case ClientCertificateType.dss_fixed_dh:
case ClientCertificateType.ecdsa_sign:
break;
default:
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
public override void ProcessClientCredentials(TlsCredentials clientCredentials)
{
if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
throw new TlsFatalAlert(AlertDescription.internal_error);
if (clientCredentials is TlsAgreementCredentials)
{
// TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
}
else if (clientCredentials is TlsSignerCredentials)
{
// OK
}
else
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
public override void GenerateClientKeyExchange(Stream output)
{
/*
* RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman
* key, then Yc is implicit and does not need to be sent again. In this case, the Client Key
* Exchange message will be sent, but will be empty.
*/
if (mAgreementCredentials == null)
{
this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
mDHParameters, output);
}
}
public override void ProcessClientCertificate(Certificate clientCertificate)
{
if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
// TODO Extract the public key
// TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey
}
public override void ProcessClientKeyExchange(Stream input)
{
if (mDHAgreePublicKey != null)
{
// For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate
return;
}
this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters);
}
public override byte[] GeneratePremasterSecret()
{
if (mAgreementCredentials != null)
{
return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey);
}
if (mDHAgreePrivateKey != null)
{
return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
}
throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
}
#pragma warning restore
#endif