internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions) { AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation; ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols; EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols); EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy; RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; } else if (sslServerAuthenticationOptions.ServerCertificate is X509Certificate2 certificateWithKey && certificateWithKey.HasPrivateKey) { // given cert is X509Certificate2 with key. We can use it directly. CertificateContext = SslStreamCertificateContext.Create(certificateWithKey); } if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null) { CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback; } }
internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions) { // Common options. AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation; ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols; CheckCertName = false; EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols); EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy; IsServer = true; RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"Server RemoteCertRequired: {RemoteCertRequired}."); } TargetHost = string.Empty; // Server specific options. CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; } else if (sslServerAuthenticationOptions.ServerCertificate != null) { X509Certificate2?certificateWithKey = sslServerAuthenticationOptions.ServerCertificate as X509Certificate2; if (certificateWithKey != null && certificateWithKey.HasPrivateKey) { // given cert is X509Certificate2 with key. We can use it directly. CertificateContext = SslStreamCertificateContext.Create(certificateWithKey, null); } else { // This is legacy fix-up. If the Certificate did not have key, we will search stores and we // will try to find one with matching hash. certificateWithKey = SecureChannel.FindCertificateWithPrivateKey(this, true, sslServerAuthenticationOptions.ServerCertificate); if (certificateWithKey == null) { throw new AuthenticationException(SR.net_ssl_io_no_server_cert); } CertificateContext = SslStreamCertificateContext.Create(certificateWithKey); } } if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null) { CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback; } }
private static SecurityStatusPal HandshakeInternal( SafeFreeCredentials credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions, SelectClientCertificate?clientCertificateSelectionCallback) { Debug.Assert(!credential.IsInvalid); try { SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context); if ((null == context) || context.IsInvalid) { sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions); context = sslContext; } if (inputBuffer.Length > 0) { sslContext !.Write(inputBuffer); } SafeSslHandle sslHandle = sslContext !.SslContext; SecurityStatusPal status = PerformHandshake(sslHandle); if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded && clientCertificateSelectionCallback != null) { X509Certificate2?clientCertificate = clientCertificateSelectionCallback(out bool _); if (clientCertificate != null) { sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate); SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext); } // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK. status = PerformHandshake(sslHandle); } outputBuffer = sslContext.ReadPendingWrites(); return(status); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }
internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions) { if (sslServerAuthenticationOptions.ServerCertificate == null && sslServerAuthenticationOptions.ServerCertificateContext == null && sslServerAuthenticationOptions.ServerCertificateSelectionCallback == null && CertSelectionDelegate == null) { throw new NotSupportedException(SR.net_ssl_io_no_server_cert); } if ((sslServerAuthenticationOptions.ServerCertificate != null || sslServerAuthenticationOptions.ServerCertificateContext != null || CertSelectionDelegate != null) && sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null) { throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(ServerCertificateSelectionCallback))); } if (CertValidationDelegate == null) { CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback; } else if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null && CertValidationDelegate != sslServerAuthenticationOptions.RemoteCertificateValidationCallback) { // Callback was set in constructor to differet value. throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(RemoteCertificateValidationCallback))); } IsServer = true; AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation; ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols; EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols); EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy; RemoteCertRequired = sslServerAuthenticationOptions.ClientCertificateRequired; CipherSuitesPolicy = sslServerAuthenticationOptions.CipherSuitesPolicy; CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode; if (sslServerAuthenticationOptions.ServerCertificateContext != null) { CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext; } else if (sslServerAuthenticationOptions.ServerCertificate != null) { X509Certificate2?certificateWithKey = sslServerAuthenticationOptions.ServerCertificate as X509Certificate2; if (certificateWithKey != null && certificateWithKey.HasPrivateKey) { // given cert is X509Certificate2 with key. We can use it directly. CertificateContext = SslStreamCertificateContext.Create(certificateWithKey, null); } else { // This is legacy fix-up. If the Certificate did not have key, we will search stores and we // will try to find one with matching hash. certificateWithKey = SslStream.FindCertificateWithPrivateKey(this, true, sslServerAuthenticationOptions.ServerCertificate); if (certificateWithKey == null) { throw new AuthenticationException(SR.net_ssl_io_no_server_cert); } CertificateContext = SslStreamCertificateContext.Create(certificateWithKey); } } if (sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null) { ServerCertSelectionDelegate = sslServerAuthenticationOptions.ServerCertificateSelectionCallback; } }
internal static SslStreamCertificateContext Create( X509Certificate2 target, X509Certificate2Collection?additionalCertificates, bool offline, SslCertificateTrust?trust, bool noOcspFetch) { if (!target.HasPrivateKey) { throw new NotSupportedException(SR.net_ssl_io_no_server_cert); } X509Certificate2[] intermediates = Array.Empty <X509Certificate2>(); X509Certificate2? root = null; using (X509Chain chain = new X509Chain()) { if (additionalCertificates != null) { foreach (X509Certificate cert in additionalCertificates) { chain.ChainPolicy.ExtraStore.Add(cert); } } chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.DisableCertificateDownloads = offline; bool chainStatus = chain.Build(target); if (!chainStatus && NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, $"Failed to build chain for {target.Subject}"); } int count = chain.ChainElements.Count - 1; // Some platforms (e.g. Android) can't ignore all verification and will return zero // certificates on failure to build a chain. Treat this as not finding any intermediates. if (count >= 0) { #pragma warning disable 0162 // Disable unreachable code warning. TrimRootCertificate is const bool = false on some platforms if (TrimRootCertificate) { count--; root = chain.ChainElements[chain.ChainElements.Count - 1].Certificate; foreach (X509ChainStatus status in chain.ChainStatus) { if (status.Status.HasFlag(X509ChainStatusFlags.PartialChain)) { // The last cert isn't a root cert count++; root = null; break; } } } #pragma warning restore 0162 // Count can be zero for a self-signed certificate, or a cert issued directly from a root. if (count > 0 && chain.ChainElements.Count > 1) { intermediates = new X509Certificate2[count]; for (int i = 0; i < count; i++) { intermediates[i] = chain.ChainElements[i + 1].Certificate; } } // Dispose the copy of the target cert. chain.ChainElements[0].Certificate.Dispose(); // Dispose the last cert, if we didn't include it. for (int i = count + 1; i < chain.ChainElements.Count; i++) { chain.ChainElements[i].Certificate.Dispose(); } } } SslStreamCertificateContext ctx = new SslStreamCertificateContext(target, intermediates, trust); // On Linux, AddRootCertificate will start a background download of an OCSP response, // unless this context was built "offline", or this came from the internal Create(X509Certificate2) ctx.SetNoOcspFetch(offline || noOcspFetch); ctx.AddRootCertificate(root); return(ctx); }
private static SecurityStatusPal HandshakeInternal( SecureChannel secureChannel, SafeFreeCredentials credential, ref SafeDeleteSslContext?context, ReadOnlySpan <byte> inputBuffer, ref byte[]?outputBuffer, SslAuthenticationOptions sslAuthenticationOptions) { Debug.Assert(!credential.IsInvalid); try { SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context); if ((null == context) || context.IsInvalid) { sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions); context = sslContext; if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) && !sslAuthenticationOptions.IsServer) { Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost); } if (sslAuthenticationOptions.CertificateContext == null && sslAuthenticationOptions.CertSelectionDelegate != null) { // certificate was not provided but there is user callback. We can break handshake if server asks for certificate // and we can try to get it based on remote certificate and trusted issuers. Interop.AppleCrypto.SslBreakOnCertRequested(sslContext.SslContext, true); } if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) { Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext); } } if (inputBuffer.Length > 0) { sslContext !.Write(inputBuffer); } SafeSslHandle sslHandle = sslContext !.SslContext; SecurityStatusPal status = PerformHandshake(sslHandle); if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded) { X509Certificate2?clientCertificate = secureChannel.SelectClientCertificate(out _); if (clientCertificate != null) { sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate); SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext); } // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK. status = PerformHandshake(sslHandle); } outputBuffer = sslContext.ReadPendingWrites(); return(status); } catch (Exception exc) { return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc)); } }