Skip to content

[API Proposal]: Make some System.Net.Security functions/properties public for System.Net.Quic #67552

@ManickaP

Description

@ManickaP

Background and motivation

  1. SslStreamCertificateContext
    In System.Net.Quic, we're handling certificates from SslServerAuthenticationOptions and need to pass them to msquic. Since SslServerAuthenticationOptions allows to specify certificate with its intermediates via SslStreamCertificateContext, we need to be able to extract both properties from the class in order to convert them and pass them to msquic.

  2. SslClientHelloInfo
    We'll also be adding our version of ServerOptionsSelectionCallback:

    public delegate ValueTask<SslServerAuthenticationOptions> ServerOptionsSelectionCallback(SslStream stream, SslClientHelloInfo clientHelloInfo, object? state, CancellationToken cancellationToken);

    And we'll need to be able to construct SslClientHelloInfo struct. Otherwise, we'll be left with reflection here as well.

  3. Current SslStreamCertificateContext takes list of additional certificates. But when Create method is called it is not clear if X509Chain build succeeds and how the actual list looks.
    Exposing the IntermediateCertificates would make any investigations easier

  4. SslStreamCertificateContext is not iDisposable (unfortunately).
    Exposing the inner certificates possibly allows some cleanup if needed. (also creates risk of mishandling)

API Proposal

  1. SslStreamCertificateContext
// Public ctors, but getters are internal.
public class SslStreamCertificateContext
{
-   internal readonly X509Certificate2 Certificate;
+   public readonly X509Certificate2 TargetCertificate { get; }
+   public ReadOnlyMemory<X509Certificate2> IntermediateCertificates { get; }
    // public ctors
}

Create method calls the certificate target and that seems too ambiguous. The proposal is to call it TaregtCertificate to make it somewhat closer or we can use the current internal Certificate (that is pretty generic as well)

We also talk about ReadOnlySpan<X509Certificate2> for the IntermediateCertificates but the consensus was to use Memory as more flexible. Current implementation use array under the cover.

  1. SslClientHelloInfo
// It has public getters, but cannot be constructed with values outside of System.Net.Security.
public readonly struct SslClientHelloInfo
{
    public readonly string ServerName { get; }
    public readonly SslProtocols SslProtocols { get; }

-   internal SslClientHelloInfo(string serverName, SslProtocols sslProtocols);
+   public SslClientHelloInfo(string serverName, SslProtocols sslProtocols);
}

API Usage

  1. SslStreamCertificateContext
if (sslOptions.ServerCertificateContext is not null) 
{
    certificate = sslOptions.ServerCertificateContext.ContextCertificate;
    intermediaries = sslOptions.ServerCertificateContext.ContextChain;
}
  1. SslClientHelloInfo
SslClientHelloInfo sslClientHelloInfo = new SslClientHelloInfo(targetHost, SslProtocols.Tls13);

Alternative Designs

  1. SslStreamCertificateContext
    Move the whole logic around certificates to System.Net.Security and get out of it only ASN1 blob (which we need for msquic).

  2. SslClientHelloInfo
    Not much options here, possibly static create method.

For both, InternalsVisibleTo. I'm aware it's "forbidden" in runtime, but I don't know why.
For both, merging System.Net.Security with System.Net.Quic. This was voted against in our team discussion, unless we want to merge whole lot more and create omnipotent System.Net.dll.

  1. Use reflection
    That was done in early 7.0. Not great for obvious reason.

  2. Use semi-public methods (current state)
    Needed properties and methods are public but not in ref assembly.
    Noted in SslStreamCertificateContext has public fields in its implementation that aren't in the contract #72226 .

Risks

Not much. We'd be only exposing readonly getters and struct ctor.

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.Net.SecurityblockingMarks issues that we want to fast track in order to unblock other important work

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions