@@ -281,7 +281,7 @@ public void Load()
281281
282282 // Compare to UseHttps(httpsOptions => { })
283283 var httpsOptions = new HttpsConnectionAdapterOptions ( ) ;
284- ServerOptionsSelectionCallback serverOptionsCallback = null ;
284+ SniOptionsSelector sniOptionsSelector = null ;
285285
286286 if ( https )
287287 {
@@ -318,8 +318,7 @@ public void Load()
318318 }
319319 else
320320 {
321- serverOptionsCallback = ( stream , clientHelloInfo , state , cancellationToken ) =>
322- SniCallback ( httpsOptions , listenOptions . Protocols , endpoint , clientHelloInfo ) ;
321+ sniOptionsSelector = new SniOptionsSelector ( this , endpoint , httpsOptions , listenOptions . Protocols ) ;
323322 }
324323 }
325324
@@ -343,7 +342,7 @@ public void Load()
343342 // EndpointDefaults or configureEndpoint may have added an https adapter.
344343 if ( https && ! listenOptions . IsTls )
345344 {
346- if ( serverOptionsCallback is null )
345+ if ( sniOptionsSelector is null )
347346 {
348347 if ( httpsOptions . ServerCertificate == null && httpsOptions . ServerCertificateSelector == null )
349348 {
@@ -354,7 +353,7 @@ public void Load()
354353 }
355354 else
356355 {
357- listenOptions . UseHttps ( serverOptionsCallback ) ;
356+ listenOptions . UseHttps ( ServerOptionsSelectionCallback , sniOptionsSelector ) ;
358357 }
359358 }
360359
@@ -367,80 +366,11 @@ public void Load()
367366 return ( endpointsToStop , endpointsToStart ) ;
368367 }
369368
370- private ValueTask < SslServerAuthenticationOptions > SniCallback (
371- HttpsConnectionAdapterOptions httpsOptions ,
372- HttpProtocols endpointDefaultHttpProtocols ,
373- EndpointConfig endpoint ,
374- SslClientHelloInfo clientHelloInfo )
369+ private static ValueTask < SslServerAuthenticationOptions > ServerOptionsSelectionCallback ( SslStream stream , SslClientHelloInfo clientHelloInfo , object state , CancellationToken cancellationToken )
375370 {
376- const string wildcardHost = "*" ;
377- const string wildcardPrefix = "*." ;
378-
379- var sslServerOptions = new SslServerAuthenticationOptions ( ) ;
380- var serverName = clientHelloInfo . ServerName ;
381- SniConfig sniConfig = null ;
382-
383- if ( ! string . IsNullOrEmpty ( serverName ) )
384- {
385- foreach ( var ( name , sniConfigCandidate ) in endpoint . SNI )
386- {
387- if ( name . Equals ( serverName , StringComparison . OrdinalIgnoreCase ) )
388- {
389- sniConfig = sniConfigCandidate ;
390- break ;
391- }
392- // Note that we only slice off the `*`. We want to match the leading `.` also.
393- else if ( name . StartsWith ( wildcardPrefix , StringComparison . Ordinal )
394- && serverName . EndsWith ( name . Substring ( wildcardHost . Length ) , StringComparison . OrdinalIgnoreCase )
395- && name . Length > ( sniConfig ? . Name . Length ?? 0 ) )
396- {
397- sniConfig = sniConfigCandidate ;
398- }
399- else if ( name . Equals ( wildcardHost , StringComparison . Ordinal ) )
400- {
401- sniConfig ??= sniConfigCandidate ;
402- }
403- }
404- }
405-
406- sslServerOptions . ServerCertificate = LoadCertificate ( sniConfig ? . Certificate , endpoint . Name ) ?? LoadEndpointOrDefaultCertificate ( httpsOptions , endpoint ) ;
407-
408- if ( sslServerOptions . ServerCertificate is null )
409- {
410- throw new InvalidOperationException ( CoreStrings . NoCertSpecifiedNoDevelopmentCertificateFound ) ;
411- }
412-
413- sslServerOptions . EnabledSslProtocols = sniConfig ? . SslProtocols ?? httpsOptions . SslProtocols ;
414- HttpsConnectionMiddleware . ConfigureAlpn ( sslServerOptions , sniConfig ? . Protocols ?? endpointDefaultHttpProtocols ) ;
415-
416- var clientCertificateMode = sniConfig ? . ClientCertificateMode ?? httpsOptions . ClientCertificateMode ;
417-
418- if ( clientCertificateMode != ClientCertificateMode . NoCertificate )
419- {
420- sslServerOptions . ClientCertificateRequired = true ;
421- sslServerOptions . RemoteCertificateValidationCallback = ( sender , certificate , chain , sslPolicyErrors ) =>
422- HttpsConnectionMiddleware . RemoteCertificateValidationCallback ( clientCertificateMode , httpsOptions . ClientCertificateValidation , certificate , chain , sslPolicyErrors ) ;
423- }
424-
425- return new ValueTask < SslServerAuthenticationOptions > ( sslServerOptions ) ;
426- }
427-
428- private X509Certificate2 LoadEndpointOrDefaultCertificate ( HttpsConnectionAdapterOptions httpsOptions , EndpointConfig endpoint )
429- {
430- // Specified
431- httpsOptions . ServerCertificate = LoadCertificate ( endpoint . Certificate , endpoint . Name )
432- ?? httpsOptions . ServerCertificate ;
433-
434- if ( httpsOptions . ServerCertificate == null && httpsOptions . ServerCertificateSelector == null )
435- {
436- // Fallback
437- Options . ApplyDefaultCert ( httpsOptions ) ;
438-
439- // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
440- endpoint . Certificate = DefaultCertificateConfig ;
441- }
442-
443- return httpsOptions . ServerCertificate ;
371+ var sniOptionsSelector = ( SniOptionsSelector ) state ;
372+ var options = sniOptionsSelector . GetOptions ( clientHelloInfo . ServerName ) ;
373+ return new ValueTask < SslServerAuthenticationOptions > ( options ) ;
444374 }
445375
446376 private void LoadDefaultCert ( ConfigurationReader configReader )
@@ -531,7 +461,7 @@ private bool TryGetCertificatePath(out string path)
531461 return path != null ;
532462 }
533463
534- private X509Certificate2 LoadCertificate ( CertificateConfig certInfo , string endpointName )
464+ internal X509Certificate2 LoadCertificate ( CertificateConfig certInfo , string endpointName )
535465 {
536466 if ( certInfo is null )
537467 {
@@ -622,6 +552,24 @@ static X509Certificate2 GetCertificate(string certificatePath)
622552 }
623553 }
624554
555+ internal X509Certificate2 LoadEndpointOrDefaultCertificate ( HttpsConnectionAdapterOptions httpsOptions , EndpointConfig endpoint )
556+ {
557+ // Specified
558+ httpsOptions . ServerCertificate = LoadCertificate ( endpoint . Certificate , endpoint . Name )
559+ ?? httpsOptions . ServerCertificate ;
560+
561+ if ( httpsOptions . ServerCertificate == null && httpsOptions . ServerCertificateSelector == null )
562+ {
563+ // Fallback
564+ Options . ApplyDefaultCert ( httpsOptions ) ;
565+
566+ // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
567+ endpoint . Certificate = DefaultCertificateConfig ;
568+ }
569+
570+ return httpsOptions . ServerCertificate ;
571+ }
572+
625573 private static X509Certificate2 AttachPemRSAKey ( X509Certificate2 certificate , string keyText , string password )
626574 {
627575 using var rsa = RSA . Create ( ) ;
0 commit comments