aspnetcore/tools/httpsys.ps1

394 lines
13 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (c) .NET Foundation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
##############################################################################
# Example
# $result = .\httpsys.ps1 -Command Get-SslBinding -IpAddress "0x00" -Port 46300
# .\httpsys.ps1 -Command Add-SslBinding -IpAddress "0x00" -Port 46300 Thumbprint $result.CertificateHash
# .\httpsys.ps1 -Command Delete-SslBinding -IpAddress "0x00" -Port 46300
##############################################################################
Param (
[parameter(Mandatory=$true , Position=0)]
[ValidateSet("Add-SslBinding",
"Delete-SslBinding",
"Get-SslBinding")]
[string]
$Command,
[parameter()]
[string]
$IpAddress,
[parameter()]
[string]
$Port,
[parameter()]
[string]
$Thumbprint,
[parameter()]
[string]
$TargetSSLStore,
[parameter()]
[string]
$AppId,
[parameter()]
[System.Net.IPEndPoint]
$IpEndPoint
)
# adjust parameter variables
if (-not $IpEndPoint)
{
if ($IpAddress -and $Port)
{
$IpEndPoint = New-Object "System.Net.IPEndPoint" -ArgumentList $IpAddress,$Port
}
}
if (-not $TargetSSLStore)
{
$TargetSSLStore = "Cert:\LocalMachine\My"
}
$StoreName = ($TargetSSLStore.Split("\") | Select-Object -Last 1).Trim()
$Certificate = Get-Item "$TargetSSLStore\$Thumbprint"
if (-not $AppId)
{
# Assign a random GUID for $AppId
$AppId = [guid]::NewGuid()
}
$cs = '
namespace Microsoft.IIS.Administration.Setup {
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.ComponentModel;
public class Http {
public const int HTTP_INITIALIZE_CONFIG = 2;
public const int HTTP_SERVICE_CONFIG_SSLCERT_INFO = 1;
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
public static extern uint HttpDeleteServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
public static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, IntPtr pReserved);
[DllImport("httpapi.dll", EntryPoint = "HttpQueryServiceConfiguration",
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern uint HttpQueryServiceConfiguration(
IntPtr serviceHandle,
HTTP_SERVICE_CONFIG_ID configID,
ref HTTP_SERVICE_CONFIG_SSL_QUERY pInputConfigInfo,
UInt32 InputConfigInfoLength,
IntPtr pOutputConfigInfo,
UInt32 OutputConfigInfoLength,
[In, Out] ref UInt32 pReturnLength,
IntPtr pOverlapped
);
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
public static extern uint HttpSetServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
public static extern uint HttpTerminate(uint flags, IntPtr pReserved);
public static HTTP_SERVICE_CONFIG_SSL_SET MarshalConfigSslSet(IntPtr ptr) {
return (HTTP_SERVICE_CONFIG_SSL_SET)Marshal.PtrToStructure(ptr, typeof(HTTP_SERVICE_CONFIG_SSL_SET));
}
}
public enum HTTP_SERVICE_CONFIG_ID {
HttpServiceConfigIPListenList,
HttpServiceConfigSSLCertInfo,
HttpServiceConfigUrlAclInfo,
HttpServiceConfigMax
}
public enum HTTP_SERVICE_CONFIG_QUERY_TYPE {
HttpServiceConfigQueryExact,
HttpServiceConfigQueryNext,
HttpServiceConfigQueryMax
}
[StructLayout(LayoutKind.Sequential)]
public struct HTTPAPI_VERSION {
public ushort HttpApiMajorVersion;
public ushort HttpApiMinorVersion;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct HTTP_SERVICE_CONFIG_SSL_KEY {
public IntPtr pIpPort;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct HTTP_SERVICE_CONFIG_SSL_QUERY {
public HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc;
public IntPtr KeyDesc;
public Int32 dwToken;
}
[StructLayout(LayoutKind.Sequential)]
public struct HTTP_SERVICE_CONFIG_SSL_SET {
public IntPtr KeyDesc;
public uint SslHashLength;
public IntPtr pSslHash;
public Guid AppId;
[MarshalAs(UnmanagedType.LPWStr)]
public string pSslCertStoreName;
public int DefaultCertCheckMode;
public int DefaultRevocationFreshnessTime;
public int DefaultRecovationUrlRetrievalTimeout;
[MarshalAs(UnmanagedType.LPWStr)]
public string pDefaultSslCtlIdentifier;
[MarshalAs(UnmanagedType.LPWStr)]
public string pDefaultSslCtlStoreName;
public int DefaultFlags;
}
}
'
$SUCCESS = 0
function InitializeInterop() {
try {
[Microsoft.IIS.Administration.Setup.Http] | Out-Null
}
catch {
Add-Type $cs
}
}
function GetIpEndpointBytes($_ipEndpoint) {
$socketAddress = $_ipEndpoint.Serialize()
$ipBytes = [System.Array]::CreateInstance([System.Byte], $socketAddress.Size)
for ($i = 0; $i -lt $socketAddress.Size; $i++) {
$ipBytes[$i] = $socketAddress[$i]
}
return $ipBytes
}
function GetBindingInfo($sslConfig) {
$hash = [System.Array]::CreateInstance([System.Byte], [int]($sslConfig.SslHashLength))
[System.Runtime.InteropServices.Marshal]::Copy($sslConfig.pSslHash, $hash, 0, $sslConfig.SslHashLength)
$socketAddressLength = 16
$sa = [System.Array]::CreateInstance([System.Byte], $socketAddressLength)
[System.Runtime.InteropServices.Marshal]::Copy($sslConfig.KeyDesc, $sa, 0, $socketAddressLength)
$socketAddress = New-Object "System.Net.SocketAddress" -ArgumentList ([System.Net.Sockets.AddressFamily]::InterNetwork, $socketAddressLength)
for ($i = 0; $i -lt $sa.Length; $i++) {
$socketAddress[$i] = $sa[$i]
}
$ep = New-Object "System.Net.IPEndPoint" -ArgumentList ([ipaddress]::Any, 0)
$endpoint = [System.Net.IPEndPoint]$ep.Create($socketAddress)
$ret = @{}
$ret.CertificateHash = [System.BitConverter]::ToString($hash).Replace("-", "")
$ret.AppId = $sslConfig.AppId
$ret.IpEndpoint = $endpoint
return $ret
}
function InitializeHttpSys() {
$v = New-Object "Microsoft.IIS.Administration.Setup.HTTPAPI_VERSION"
$V.HttpApiMajorVersion = 1
$v.HttpApiMinorVersion = 0
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpInitialize($v, [Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
if ($result -ne $SUCCESS) {
Write-Warning "Error initializing Http API"
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
}
return $result
}
function TerminateHttpSys() {
return [Microsoft.IIS.Administration.Setup.Http]::HttpTerminate([Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
}
function Add-SslBinding($_ipEndpoint, $_certificate, $_appId) {
if ($_ipEndpoint -eq $null) {
throw "Ip Endpoint required."
}
if ($_certificate -eq $null) {
throw "Certificate required."
}
if ($appId -eq $null) {
throw "App id required."
}
<# FYI, [System.Guid]::Parse() is not supported in lower version of powershell
if (-not($_appId -is [System.Guid])) {
$_appId = [System.Guid]::Parse($_appId)
}
#>
setSslConfiguration $_ipEndpoint $_certificate $_appId
}
function Delete-SslBinding($_ipEndpoint) {
if ($_ipEndpoint -eq $null) {
throw "Ip Endpoint required."
}
setSslConfiguration $_ipEndpoint $null $([System.Guid]::Empty)
}
function Get-SslBinding($_ipEndpoint) {
if ($_ipEndpoint -eq $null) {
throw "Ip Endpoint required."
}
$bufferSize = 4096
try {
InitializeHttpSys| Out-Null
$ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
$hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
$pIp = $hIp.AddrOfPinnedObject()
$queryParam = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_QUERY"
$queryParam.QueryDesc = [Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_QUERY_TYPE]::HttpServiceConfigQueryExact
$queryParam.dwToken = 0
$queryParam.KeyDesc = $pIp
$returnLen = 0
$pReturnSet = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($bufferSize)
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpQueryServiceConfiguration(
[System.IntPtr]::Zero,
[Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_ID]::HttpServiceConfigSSLCertInfo,
[ref] $queryParam,
[uint32]([System.Runtime.InteropServices.Marshal]::SizeOf($queryParam)),
$pReturnSet,
$bufferSize,
[ref] $returnLen,
[System.IntPtr]::Zero)
if ($result -eq 2) {
# File not found
return $null
}
if ($result -ne $SUCCESS) {
Write-Warning "Error reading Ssl Cert Configuration"
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
}
$sslConfig = [Microsoft.IIS.Administration.Setup.Http]::MarshalConfigSslSet($pReturnSet)
return GetBindingInfo $sslConfig
}
finally {
if ($hIp -ne $null) {
$hIp.Free()
$hIp = $null
}
if ($pReturnSet -ne [System.IntPtr]::Zero) {
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($pReturnSet)
$pReturnSet = [System.IntPtr]::Zero
}
TerminateHttpSys | Out-Null
}
}
function setSslConfiguration($_ipEndpoint, $_certificate, $_appId) {
try {
InitializeHttpSys| Out-Null
$sslSet = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_SET"
$sslSetSize = [System.Runtime.InteropServices.Marshal]::SizeOf($sslSet)
$ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
$hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
$pIp = $hIp.AddrOfPinnedObject()
$sslSet.KeyDesc = $pIp # IntPtr
$sslSet.SslHashLength = 0
$sslSet.pSslHash = [System.IntPtr]::Zero
$sslSet.pSslCertStoreName = [System.IntPtr]::Zero
$sslSet.AppId = $_appId
if ($_certificate -ne $null) {
# Create binding
$certBytes = $_certificate.GetCertHash()
$hCertBytes = [System.Runtime.InteropServices.GCHandle]::Alloc($certBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
$pCertBytes = $hCertBytes.AddrOfPinnedObject()
$sslSet.SslHashLength = 20
$sslSet.pSslHash = $pCertBytes
$sslSet.pSslCertStoreName = $StoreName
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpSetServiceConfiguration([System.IntPtr]::Zero,
[Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
[ref]$sslSet,
$sslSetSize,
[System.IntPtr]::Zero)
}
else {
#Delete binding
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpDeleteServiceConfiguration([System.IntPtr]::Zero,
[Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
[ref]$sslSet,
$sslSetSize,
[System.IntPtr]::Zero)
}
if ($result -ne $SUCCESS) {
Write-Warning "Error setting Ssl Cert Configuration"
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
}
}
finally {
if ($hIp -ne $null) {
$hIp.Free()
$hIp = $null
}
if ($hCertBytes -ne $null) {
$hCertBytes.Free()
$hCertBytes = $null
}
TerminateHttpSys| Out-Null
}
}
InitializeInterop
switch ($Command)
{
"Add-SslBinding"
{
return Add-SslBinding $IpEndPoint $Certificate $AppId
}
"Delete-SslBinding"
{
return Delete-SslBinding $IpEndpoint
}
"Get-SslBinding"
{
return Get-SslBinding $IpEndpoint
}
default
{
throw "Unknown command"
}
}