parent
d0de73684d
commit
f3b0fbe207
|
|
@ -26,6 +26,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
Negotiate = 8,
|
Negotiate = 8,
|
||||||
Kerberos = 16,
|
Kerberos = 16,
|
||||||
}
|
}
|
||||||
|
public enum ClientCertificateMethod
|
||||||
|
{
|
||||||
|
NoCertificate = 0,
|
||||||
|
AllowCertificate = 1,
|
||||||
|
AllowRenegotation = 2,
|
||||||
|
}
|
||||||
public enum Http503VerbosityLevel : long
|
public enum Http503VerbosityLevel : long
|
||||||
{
|
{
|
||||||
Basic = (long)0,
|
Basic = (long)0,
|
||||||
|
|
@ -46,6 +52,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
public HttpSysOptions() { }
|
public HttpSysOptions() { }
|
||||||
public bool AllowSynchronousIO { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public bool AllowSynchronousIO { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public Microsoft.AspNetCore.Server.HttpSys.AuthenticationManager Authentication { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public Microsoft.AspNetCore.Server.HttpSys.AuthenticationManager Authentication { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
|
public Microsoft.AspNetCore.Server.HttpSys.ClientCertificateMethod ClientCertificateMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public bool EnableResponseCaching { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public bool EnableResponseCaching { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public Microsoft.AspNetCore.Server.HttpSys.Http503VerbosityLevel Http503Verbosity { get { throw null; } set { } }
|
public Microsoft.AspNetCore.Server.HttpSys.Http503VerbosityLevel Http503Verbosity { get { throw null; } set { } }
|
||||||
public int MaxAccepts { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public int MaxAccepts { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes the client certificate negotiation method for HTTPS connections.
|
||||||
|
/// </summary>
|
||||||
|
public enum ClientCertificateMethod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate will not be populated on the request.
|
||||||
|
/// </summary>
|
||||||
|
NoCertificate = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate will be populated if already present at the start of a request.
|
||||||
|
/// </summary>
|
||||||
|
AllowCertificate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The TLS session can be renegotiated to request a client certificate.
|
||||||
|
/// </summary>
|
||||||
|
AllowRenegotation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -316,7 +316,17 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
{
|
{
|
||||||
if (IsNotInitialized(Fields.ClientCertificate))
|
if (IsNotInitialized(Fields.ClientCertificate))
|
||||||
{
|
{
|
||||||
_clientCert = Request.GetClientCertificateAsync().Result; // TODO: Sync;
|
var method = _requestContext.Server.Options.ClientCertificateMethod;
|
||||||
|
if (method == ClientCertificateMethod.AllowCertificate)
|
||||||
|
{
|
||||||
|
_clientCert = Request.ClientCertificate;
|
||||||
|
}
|
||||||
|
else if (method == ClientCertificateMethod.AllowRenegotation)
|
||||||
|
{
|
||||||
|
_clientCert = Request.GetClientCertificateAsync().Result; // TODO: Sync over async;
|
||||||
|
}
|
||||||
|
// else if (method == ClientCertificateMethod.NoCertificate) // No-op
|
||||||
|
|
||||||
SetInitialized(Fields.ClientCertificate);
|
SetInitialized(Fields.ClientCertificate);
|
||||||
}
|
}
|
||||||
return _clientCert;
|
return _clientCert;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RequestQueueMode RequestQueueMode { get; set; }
|
public RequestQueueMode RequestQueueMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates how client certificates should be populated. The default is to allow renegotation.
|
||||||
|
/// This does not change the netsh 'clientcertnegotiation' binding option which will need to be enabled for
|
||||||
|
/// ClientCertificateMethod.AllowCertificate to resolve a certificate.
|
||||||
|
/// </summary>
|
||||||
|
public ClientCertificateMethod ClientCertificateMethod { get; set; } = ClientCertificateMethod.AllowRenegotation;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum number of concurrent accepts.
|
/// The maximum number of concurrent accepts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,15 @@ using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security;
|
||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
{
|
{
|
||||||
|
|
@ -323,6 +326,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
KeyExchangeStrength = (int)handshake.KeyExchangeStrength;
|
KeyExchangeStrength = (int)handshake.KeyExchangeStrength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public X509Certificate2 ClientCertificate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_clientCert == null && SslStatus == SslStatus.ClientCert)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_clientCert = _nativeRequestContext.GetClientCertificate();
|
||||||
|
}
|
||||||
|
catch (CryptographicException ce)
|
||||||
|
{
|
||||||
|
RequestContext.Logger.LogDebug(ce, "An error occurred reading the client certificate.");
|
||||||
|
}
|
||||||
|
catch (SecurityException se)
|
||||||
|
{
|
||||||
|
RequestContext.Logger.LogDebug(se, "An error occurred reading the client certificate.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _clientCert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Populates the client certificate. The result may be null if there is no client cert.
|
// Populates the client certificate. The result may be null if there is no client cert.
|
||||||
// TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to
|
// TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to
|
||||||
// enable this, but it's unclear what Http.Sys would do.
|
// enable this, but it's unclear what Http.Sys would do.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
|
@ -518,5 +519,49 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
|
|
||||||
return new ReadOnlyDictionary<int, ReadOnlyMemory<byte>>(info);
|
return new ReadOnlyDictionary<int, ReadOnlyMemory<byte>>(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal X509Certificate2 GetClientCertificate()
|
||||||
|
{
|
||||||
|
if (_permanentlyPinned)
|
||||||
|
{
|
||||||
|
return GetClientCertificate((IntPtr)_nativeRequest, (HttpApiTypes.HTTP_REQUEST_V2*)_nativeRequest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||||
|
{
|
||||||
|
var request = (HttpApiTypes.HTTP_REQUEST_V2*)(pMemoryBlob + _bufferAlignment);
|
||||||
|
return GetClientCertificate(_originalBufferAddress, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws CryptographicException
|
||||||
|
private X509Certificate2 GetClientCertificate(IntPtr baseAddress, HttpApiTypes.HTTP_REQUEST_V2* nativeRequest)
|
||||||
|
{
|
||||||
|
var request = nativeRequest->Request;
|
||||||
|
long fixup = (byte*)nativeRequest - (byte*)baseAddress;
|
||||||
|
if (request.pSslInfo == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sslInfo = (HttpApiTypes.HTTP_SSL_INFO*)((byte*)request.pSslInfo + fixup);
|
||||||
|
if (sslInfo->SslClientCertNegotiated == 0 || sslInfo->pClientCertInfo == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientCertInfo = (HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO*)((byte*)sslInfo->pClientCertInfo + fixup);
|
||||||
|
if (clientCertInfo->pCertEncoded == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientCert = clientCertInfo->pCertEncoded + fixup;
|
||||||
|
byte[] certEncoded = new byte[clientCertInfo->CertEncodedSize];
|
||||||
|
Marshal.Copy((IntPtr)clientCert, certEncoded, 0, certEncoded.Length);
|
||||||
|
return new X509Certificate2(certEncoded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue