Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal interface ISSPIInterface
int EnumerateSecurityPackages(out int pkgnum, out SafeFreeContextBuffer pkgArray);
int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, ref SafeSspiAuthDataHandle authdata, out SafeFreeCredentials outCredential);
int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, ref Interop.SspiCli.SCHANNEL_CRED authdata, out SafeFreeCredentials outCredential);
unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, Interop.SspiCli.SCH_CREDENTIALS* authdata, out SafeFreeCredentials outCredential);
int AcquireDefaultCredential(string moduleName, Interop.SspiCli.CredentialUse usage, out SafeFreeCredentials outCredential);
int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
int InitializeSecurityContext(ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, InputSecurityBuffers inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags);
Expand Down
105 changes: 105 additions & 0 deletions src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,97 @@ public enum Flags
}
}

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct SCH_CREDENTIALS
{
public const int CurrentVersion = 0x5;

public int dwVersion;
public int dwCredformat;
public int cCreds;

// ptr to an array of pointers
// There is a hack done with this field. AcquireCredentialsHandle requires an array of
// certificate handles; we only ever use one. In order to avoid pinning a one element array,
// we copy this value onto the stack, create a pointer on the stack to the copied value,
// and replace this field with the pointer, during the call to AcquireCredentialsHandle.
// Then we fix it up afterwards. Fine as long as all the SSPI credentials are not
// supposed to be threadsafe.
public IntPtr paCred;

public IntPtr hRootStore; // == always null, OTHERWISE NOT RELIABLE
public int cMappers;
public IntPtr aphMappers; // == always null, OTHERWISE NOT RELIABLE

public int dwSessionLifespan;
public SCH_CREDENTIALS.Flags dwFlags;
public int cTlsParameters;
public TLS_PARAMETERS* pTlsParameters;

[Flags]
public enum Flags
{
Zero = 0,
SCH_CRED_NO_SYSTEM_MAPPER = 0x02,
SCH_CRED_NO_SERVERNAME_CHECK = 0x04,
SCH_CRED_MANUAL_CRED_VALIDATION = 0x08,
SCH_CRED_NO_DEFAULT_CREDS = 0x10,
SCH_CRED_AUTO_CRED_VALIDATION = 0x20,
SCH_CRED_USE_DEFAULT_CREDS = 0x40,
SCH_DISABLE_RECONNECTS = 0x80,
SCH_CRED_REVOCATION_CHECK_END_CERT = 0x100,
SCH_CRED_REVOCATION_CHECK_CHAIN = 0x200,
SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x400,
SCH_CRED_IGNORE_NO_REVOCATION_CHECK = 0x800,
SCH_CRED_IGNORE_REVOCATION_OFFLINE = 0x1000,
SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE = 0x2000,
SCH_SEND_ROOT_CERT = 0x40000,
SCH_SEND_AUX_RECORD = 0x00200000,
SCH_USE_STRONG_CRYPTO = 0x00400000,
SCH_USE_PRESHAREDKEY_ONLY = 0x800000,
SCH_ALLOW_NULL_ENCRYPTION = 0x02000000,
}
}

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct TLS_PARAMETERS
{
public int cAlpnIds; // Valid for server applications only. Must be zero otherwise. Number of ALPN IDs in rgstrAlpnIds; set to 0 if applies to all.
public IntPtr rgstrAlpnIds; // Valid for server applications only. Must be NULL otherwise. Array of ALPN IDs that the following settings apply to; set to NULL if applies to all.
public uint grbitDisabledProtocols; // List protocols you DO NOT want negotiated.
public int cDisabledCrypto; // Number of CRYPTO_SETTINGS structures; set to 0 if there are none.
public CRYPTO_SETTINGS* pDisabledCrypto; // Array of CRYPTO_SETTINGS structures; set to NULL if there are none;
public TLS_PARAMETERS.Flags dwFlags; // Optional flags to pass; set to 0 if there are none.

[Flags]
public enum Flags
{
Zero = 0,
TLS_PARAMS_OPTIONAL = 0x01, // Valid for server applications only. Must be zero otherwise.
// TLS_PARAMETERS that will only be honored if they do not cause this server to terminate the handshake.
}
}

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct CRYPTO_SETTINGS
{
public TlsAlgorithmUsage eAlgorithmUsage; // How this algorithm is being used.
public UNICODE_STRING* strCngAlgId; // CNG algorithm identifier.
public int cChainingModes; // Set to 0 if CNG algorithm does not have a chaining mode.
public UNICODE_STRING* rgstrChainingModes; // Set to NULL if CNG algorithm does not have a chaining mode.
public int dwMinBitLength; // Blacklist key sizes less than this. Set to 0 if not defined or CNG algorithm implies bit length.
public int dwMaxBitLength; // Blacklist key sizes greater than this. Set to 0 if not defined or CNG algorithm implies bit length.

public enum TlsAlgorithmUsage
{
TlsParametersCngAlgUsageKeyExchange, // Key exchange algorithm. RSA, ECHDE, DHE, etc.
TlsParametersCngAlgUsageSignature, // Signature algorithm. RSA, DSA, ECDSA, etc.
TlsParametersCngAlgUsageCipher, // Encryption algorithm. AES, DES, RC4, etc.
TlsParametersCngAlgUsageDigest, // Digest of cipher suite. SHA1, SHA256, SHA384, etc.
TlsParametersCngAlgUsageCertSig // Signature and/or hash used to sign certificate. RSA, DSA, ECDSA, SHA1, SHA256, etc.
}
}

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct SecBuffer
{
Expand Down Expand Up @@ -345,6 +436,20 @@ internal static extern unsafe int AcquireCredentialsHandleW(
[Out] out long timeStamp
);

[DllImport(Interop.Libraries.SspiCli, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern unsafe int AcquireCredentialsHandleW(
[In] string? principal,
[In] string moduleName,
[In] int usage,
[In] void* logonID,
[In] SCH_CREDENTIALS* authData,
[In] void* keyCallback,
[In] void* keyArgument,
ref CredHandle handlePtr,
[Out] out long timeStamp
);


[DllImport(Interop.Libraries.SspiCli, ExactSpelling = true, SetLastError = true)]
internal static extern unsafe int InitializeSecurityContextW(
ref CredHandle credentialHandle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.Credentia
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential);
}

public unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, Interop.SspiCli.SCH_CREDENTIALS* authdata, out SafeFreeCredentials outCredential)
{
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, authdata, out outCredential);
}

public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.Credentia
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, ref authdata, out outCredential);
}

public unsafe int AcquireCredentialsHandle(string moduleName, Interop.SspiCli.CredentialUse usage, Interop.SspiCli.SCH_CREDENTIALS* authdata, out SafeFreeCredentials outCredential)
{
return SafeFreeCredentials.AcquireCredentialsHandle(moduleName, usage, authdata, out outCredential);
}

public int AcceptSecurityContext(SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, InputSecurityBuffers inputBuffers, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness endianness, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
return SafeDeleteContext.AcceptSecurityContext(ref credential, ref context, inFlags, endianness, inputBuffers, ref outputBuffer, ref outFlags);
Expand Down
25 changes: 25 additions & 0 deletions src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,31 @@ public static SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secMod
return outCredential;
}

public static unsafe SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface secModule, string package, Interop.SspiCli.CredentialUse intent, Interop.SspiCli.SCH_CREDENTIALS* scc)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(null, package);
NetEventSource.Log.AcquireCredentialsHandle(package, intent, (IntPtr)scc);
}

SafeFreeCredentials? outCredential = null;
int errorCode = secModule.AcquireCredentialsHandle(
package,
intent,
scc,
out outCredential);

if (errorCode != 0)
{
if (NetEventSource.IsEnabled) NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireCredentialsHandle), $"0x{errorCode:X}"));
throw new Win32Exception(errorCode);
}

if (NetEventSource.IsEnabled) NetEventSource.Exit(null, outCredential);
return outCredential;
}

internal static int InitializeSecurityContext(ISSPIInterface secModule, ref SafeFreeCredentials? credential, ref SafeDeleteSslContext? context, string? targetName, Interop.SspiCli.ContextFlags inFlags, Interop.SspiCli.Endianness datarep, InputSecurityBuffers inputBuffers, ref SecurityBuffer outputBuffer, ref Interop.SspiCli.ContextFlags outFlags)
{
if (NetEventSource.IsEnabled) NetEventSource.Log.InitializeSecurityContext(credential, context, targetName, inFlags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ public static unsafe int AcquireCredentialsHandle(
out SafeFreeCredentials outCredential)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(null, package, intent, authdata);

int errorCode = -1;
long timeStamp;

Expand Down Expand Up @@ -318,6 +317,59 @@ public static unsafe int AcquireCredentialsHandle(

return errorCode;
}

public static unsafe int AcquireCredentialsHandle(
string package,
Interop.SspiCli.CredentialUse intent,
Interop.SspiCli.SCH_CREDENTIALS* authdata,
out SafeFreeCredentials outCredential)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(null, package, intent, (IntPtr)authdata);

int errorCode = -1;
long timeStamp;

// If there is a certificate, wrap it into an array.
// Not threadsafe.
IntPtr copiedPtr = authdata->paCred;
try
{
IntPtr certArrayPtr = new IntPtr(&copiedPtr);
if (copiedPtr != IntPtr.Zero)
{
authdata->paCred = certArrayPtr;
}

outCredential = new SafeFreeCredential_SECURITY();

errorCode = Interop.SspiCli.AcquireCredentialsHandleW(
null,
package,
(int)intent,
null,
authdata,
null,
null,
ref outCredential._handle,
out timeStamp);
}
finally
{
authdata->paCred = copiedPtr;
}

#if TRACE_VERBOSE
if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}");
#endif

if (errorCode != 0)
{
outCredential.SetHandleAsInvalid();
}

return errorCode;
}

}

//
Expand Down
4 changes: 3 additions & 1 deletion src/libraries/System.Net.Http/src/System.Net.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@
<Compile Include="System\Net\Http\SocketsHttpHandler\CurrentUserIdentityProvider.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs"
Link="Common\Interop\Windows\Interop.Libraries.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.UNICODE_STRING.cs"
Link="Common\Interop\Windows\Interop.UNICODE_STRING.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs"
Link="Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.certificates_types.cs"
Expand Down Expand Up @@ -737,4 +739,4 @@
<ItemGroup Condition=" '$(TargetsBrowser)' == 'true'">
<ProjectReference Include="..\..\System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
<Compile Include="System\Net\Windows\WebSockets\WebSocketProtocolComponent.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
Link="Common\Interop\Windows\Interop.Libraries.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.UNICODE_STRING.cs"
Link="Common\Interop\Windows\Interop.UNICODE_STRING.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs"
Link="Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs"
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.Net.Mail/src/System.Net.Mail.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
Link="Common\System\Net\Security\NetEventSource.Security.cs" />
<Compile Include="$(CommonPath)System\HexConverter.cs"
Link="Common\System\HexConverter.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.UNICODE_STRING.cs"
Link="Common\Interop\Windows\Interop.UNICODE_STRING.cs" />
</ItemGroup>
<!-- Unix specific files -->
<ItemGroup Condition="'$(TargetsUnix)'=='true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@
<!-- Interop -->
<Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
Link="Common\Interop\Windows\Interop.Libraries.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.UNICODE_STRING.cs"
Link="Common\Interop\Windows\Interop.UNICODE_STRING.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Crypt32\Interop.certificates.cs"
Link="Common\Interop\Windows\Crypt32\Interop.certificates.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Crypt32\Interop.certificates_types.cs"
Expand All @@ -152,6 +154,8 @@
Link="Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.CloseHandle.cs"
Link="Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs" />
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.RtlGetVersion.cs"
Link="Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.Alerts.cs"
Link="Common\Interop\Windows\SChannel\Interop.Alerts.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.SchProtocols.cs"
Expand Down
Loading