XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;
using System.Net;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Tls.Crypto.Impl.BC;

namespace XFESystem.Tls;

/// <summary>Actual managed TLS over the supplied platform stream; never a host HTTP adapter.</summary>
public sealed class TlsClientConnection : IDisposable
{
    private readonly TlsClientProtocol protocol;
    private readonly VerifiedClient client;
    public Stream Stream => protocol.Stream;
    public string Protocol => client.Protocol;
    public bool CertificateValidated => client.CertificateValidated;

    public TlsClientConnection(Stream platformStream, string host, TlsCertificateValidator certificates, ITlsSecurityContext platform)
    {
        ArgumentNullException.ThrowIfNull(platformStream);
        ArgumentNullException.ThrowIfNull(certificates);
        ArgumentNullException.ThrowIfNull(platform);
        if (string.IsNullOrWhiteSpace(host) || host.Length > 253 || host.Any(character => character > 127 || char.IsControl(character)) ||
            Uri.CheckHostName(host) == UriHostNameType.Unknown)
            throw new ArgumentException("TLS requires an ASCII DNS name or IP address without a port or credentials.", nameof(host));
        host = host.TrimEnd('.');
        _ = TlsSecurity.ReadUtc(platform);
        var random = TlsSecurity.CreateRandom(platform);
        client = new(host, certificates, platform, random);
        protocol = new TlsClientProtocol(platformStream);
        try
        {
            protocol.Connect(client);
            if (!client.CertificateValidated) throw new IOException("The TLS handshake did not validate the peer certificate.");
        }
        catch { TryClose(); throw; }
    }

    private void TryClose() { try { protocol.Close(); } catch { } }
    public void Dispose() => TryClose();

    private sealed class VerifiedClient(string host, TlsCertificateValidator certificates, ITlsSecurityContext platform, SecureRandom random)
        : DefaultTlsClient(new BcTlsCrypto(random)), TlsAuthentication
    {
        public bool CertificateValidated { get; private set; }
        public string Protocol { get; private set; } = "";
        public override int GetHandshakeTimeoutMillis() => 10_000;
        public override bool RequiresExtendedMasterSecret() => true;
        protected override ProtocolVersion[] GetSupportedVersions() => [ProtocolVersion.TLSv13, ProtocolVersion.TLSv12];
        protected override int[] GetSupportedCipherSuites() =>
        [
            CipherSuite.TLS_AES_128_GCM_SHA256,
            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
            CipherSuite.TLS_AES_256_GCM_SHA384,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
        ];
        protected override IList<ServerName> GetSniServerNames() => IPAddress.TryParse(host, out _) ? null! :
            [new ServerName(NameType.host_name, Encoding.ASCII.GetBytes(host))];
        protected override IList<ProtocolName> GetProtocolNames() => [ProtocolName.Http_1_1];
        protected override IList<int> GetSupportedGroups(IList<int> namedGroupRoles) => [NamedGroup.x25519, NamedGroup.secp256r1, NamedGroup.secp384r1];
        public override TlsAuthentication GetAuthentication() => this;
        public void NotifyServerCertificate(TlsServerCertificate serverCertificate)
        {
            var chain = serverCertificate.Certificate.GetCertificateList().Select(certificate => certificate.GetEncoded()).ToArray();
            certificates.Validate(host, chain, TlsSecurity.ReadUtc(platform));
            CertificateValidated = true;
        }
        public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) => null!;
        public override void NotifyHandshakeComplete()
        {
            base.NotifyHandshakeComplete();
            Protocol = m_context.SecurityParameters.NegotiatedVersion.ToString();
        }
    }
}