【问题标题】:How to download the SSL certificate from a website using PowerShell?如何使用 PowerShell 从网站下载 SSL 证书?
【发布时间】:2014-03-06 19:07:54
【问题描述】:

我想使用 PowerShell 从 https://www.outlook.com 下载 SSL 证书。 是否可以?有人可以帮我吗?

【问题讨论】:

    标签: powershell ssl ssl-certificate


    【解决方案1】:

    分享更多知识:-)

    $webRequest = [Net.WebRequest]::Create("https://www.outlook.com")
    try { $webRequest.GetResponse() } catch {}
    $cert = $webRequest.ServicePoint.Certificate
    $bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
    set-content -value $bytes -encoding byte -path "$pwd\Outlook.Com.cer"
    

    我的同事 Michael J. Lyons 与我分享了这一点。

    【讨论】:

    • Nit:Powershell 很乐意将字符串转换为枚举成员,所以$cert.Export("Cert") 是一个有效的写法。
    • 如何获得根证书或链?
    • 嗯。通过使用子类型Net.HttpWebRequest,我们可以设置$webRequest.Method = "HEAD"来节省一些带宽。
    • @Tilo 仅当客户端已经有权访问(并信任)根证书时,证书才被认为是有效的。将链条穿过电线将是多余的。但是,如果您将证书转换为 X509Certificate2,您会获得更多信息。 New-Object -TypeName "System.Security.Cryptography.X509Certificates.X509Certificate2" -ArgumentList $cert 之类的东西应该可以。
    • 这应该是公认的答案,因为它更简单
    【解决方案2】:

    您应该能够通过使用HttpWebRequest 对象上的ServicePoint 属性来获取公钥。一旦我们向相关网站发出 http 请求,就会填充这些必要的信息。

    如果向具有不受信任证书的站点发出请求,则 GetResponse 方法将引发异常,但是,ServicePoint 仍将包含 Certificate,因此我们要确保忽略 WebException,如果状态是信任失败。

    所以类似下面的东西应该可以工作:

    function Get-PublicKey
    {
        [OutputType([byte[]])]
        PARAM (
            [Uri]$Uri
        )
    
        if (-Not ($uri.Scheme -eq "https"))
        {
            Write-Error "You can only get keys for https addresses"
            return
        }
    
        $request = [System.Net.HttpWebRequest]::Create($uri)
    
        try
        {
            #Make the request but ignore (dispose it) the response, since we only care about the service point
            $request.GetResponse().Dispose()
        }
        catch [System.Net.WebException]
        {
            if ($_.Exception.Status -eq [System.Net.WebExceptionStatus]::TrustFailure)
            {
                #We ignore trust failures, since we only want the certificate, and the service point is still populated at this point
            }
            else
            {
                #Let other exceptions bubble up, or write-error the exception and return from this method
                throw
            }
        }
    
        #The ServicePoint object should now contain the Certificate for the site.
        $servicePoint = $request.ServicePoint
        $key = $servicePoint.Certificate.GetPublicKey()
        Write-Output $key
    }
    
    Get-PublicKey -Uri "https://www.bing.com"
    Get-PublicKey -Uri "https://www.facebook.com"
    

    如果您想多次调用该方法并且有些可能具有相同的地址,您可能希望通过使用@987654321@ 方法来改进该功能,因为如果已经发出请求,它将返回一个缓存版本那个网站。因此,您可以检查服务点是否已填充信息。如果没有,请发出网络请求。如果有,只需使用已经存在的信息,为自己节省一个 http 请求。

    【讨论】:

    • 这只显示了公钥的int值,Out-File内容不可用。 @RafaMarrara 的回答产生了一个有效的 .cert 文件,并且符合 OP 的“下载 SSL 证书”的请求
    【解决方案3】:

    来自http://poshcode.org/2521

    function Get-WebsiteCertificate {
      [CmdletBinding()]
      param (
        [Parameter(Mandatory=$true)] [System.Uri]
          $Uri,
        [Parameter()] [System.IO.FileInfo]
          $OutputFile,
        [Parameter()] [Switch]
          $UseSystemProxy,  
        [Parameter()] [Switch]
          $UseDefaultCredentials,
        [Parameter()] [Switch]
          $TrustAllCertificates
      )
      try {
        $request = [System.Net.WebRequest]::Create($Uri)
        if ($UseSystemProxy) {
          $request.Proxy = [System.Net.WebRequest]::DefaultWebProxy
        }
    
        if ($UseSystemProxy -and $UseDefaultCredentials) {
          $request.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
        }
    
        if ($TrustAllCertificates) {
          # Create a compilation environment
          $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
          $Compiler=$Provider.CreateCompiler()
          $Params=New-Object System.CodeDom.Compiler.CompilerParameters
          $Params.GenerateExecutable=$False
          $Params.GenerateInMemory=$True
          $Params.IncludeDebugInformation=$False
          $Params.ReferencedAssemblies.Add("System.DLL") > $null
          $TASource=@'
            namespace Local.ToolkitExtensions.Net.CertificatePolicy {
              public class TrustAll : System.Net.ICertificatePolicy {
                public TrustAll() { 
                }
                public bool CheckValidationResult(System.Net.ServicePoint sp,
                  System.Security.Cryptography.X509Certificates.X509Certificate cert, 
                  System.Net.WebRequest req, int problem) {
                  return true;
                }
              }
            }
    '@ 
          $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
          $TAAssembly=$TAResults.CompiledAssembly
    
          ## We now create an instance of the TrustAll and attach it to the ServicePointManager
          $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
          [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
        }
    
        $response = $request.GetResponse()
        $servicePoint = $request.ServicePoint
        $certificate = $servicePoint.Certificate
    
        if ($OutputFile) {
          $certBytes = $certificate.Export(
              [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert
            )
          [System.IO.File]::WriteAllBytes( $OutputFile, $certBytes )
          $OutputFile.Refresh()
          return $OutputFile
        } else {
          return $certificate
        }
      } catch {
        Write-Error "Failed to get website certificate. The error was '$_'."
        return $null
      }
    
      <#
        .SYNOPSIS
          Retrieves the certificate used by a website.
    
        .DESCRIPTION
          Retrieves the certificate used by a website. Returns either an object or file.
    
        .PARAMETER  Uri
          The URL of the website. This should start with https.
    
        .PARAMETER  OutputFile
          Specifies what file to save the certificate as.
    
        .PARAMETER  UseSystemProxy
          Whether or not to use the system proxy settings.
    
        .PARAMETER  UseDefaultCredentials
          Whether or not to use the system logon credentials for the proxy.
    
        .PARAMETER  TrustAllCertificates
          Ignore certificate errors for certificates that are expired, have a mismatched common name or are self signed.
    
        .EXAMPLE
          PS C:\> Get-WebsiteCertificate "https://www.gmail.com" -UseSystemProxy -UseDefaultCredentials -TrustAllCertificates -OutputFile C:\gmail.cer
    
        .INPUTS
          Does not accept pipeline input.
    
        .OUTPUTS
          System.Security.Cryptography.X509Certificates.X509Certificate, System.IO.FileInfo
      #>
    }
    
    function Import-Certificate {
    <#
        .SYNOPSIS
            Imports certificate in specified certificate store.
    
        .DESCRIPTION
            Imports certificate in specified certificate store.
    
        .PARAMETER  CertFile
            The certificate file to be imported.
    
        .PARAMETER  StoreNames
            The certificate store(s) in which the certificate should be imported.
    
        .PARAMETER  LocalMachine
            Using the local machine certificate store to import the certificate
    
        .PARAMETER  CurrentUser
            Using the current user certificate store to import the certificate
    
        .PARAMETER  CertPassword
            The password which may be used to protect the certificate file
    
        .EXAMPLE
            PS C:\> Import-Certificate C:\Temp\myCert.cer
    
            Imports certificate file myCert.cer into the current users personal store
    
        .EXAMPLE
            PS C:\> Import-Certificate -CertFile C:\Temp\myCert.cer -StoreNames my
    
            Imports certificate file myCert.cer into the current users personal store
    
        .EXAMPLE
            PS C:\> Import-Certificate -Cert $certificate -StoreNames my -StoreType LocalMachine
    
            Imports the certificate stored in $certificate into the local machines personal store 
    
        .EXAMPLE
            PS C:\> Import-Certificate -Cert $certificate -SN my -ST Machine
    
            Imports the certificate stored in $certificate into the local machines personal store using alias names
    
        .EXAMPLE
            PS C:\> ls cert:\currentUser\TrustedPublisher | Import-Certificate -ST Machine -SN TrustedPublisher
    
            Copies the certificates found in current users TrustedPublishers store to local machines TrustedPublisher using alias  
    
        .INPUTS
            System.String|System.Security.Cryptography.X509Certificates.X509Certificate2, System.String, System.String
    
        .OUTPUTS
            NA
    
        .NOTES
            NAME:      Import-Certificate
            AUTHOR:    Patrick Sczepanksi (Original anti121)
            VERSION:   20110502
            #Requires -Version 2.0
        .LINK
            http://poshcode.org/2643
            http://poshcode.org/1937 (Link to original script)
    
    #>
    
        [CmdletBinding()]
        param
        (
            [Parameter(ValueFromPipeline=$true,Mandatory=$true, Position=0, ParameterSetName="CertFile")]
            [System.IO.FileInfo]
            $CertFile,
    
            [Parameter(ValueFromPipeline=$true,Mandatory=$true, Position=0, ParameterSetName="Cert")]
            [System.Security.Cryptography.X509Certificates.X509Certificate2]
            $Cert,
    
            [Parameter(Position=1)]
            [Alias("SN")]
            [string[]] $StoreNames = "My",
    
            [Parameter(Position=2)]
            [Alias("Type","ST")]
            [ValidateSet("LocalMachine","Machine","CurrentUser","User")]
            [string]$StoreType = "CurrentUser",
    
            [Parameter(Position=3)]
            [Alias("Password","PW")]
            [string] $CertPassword
        )
    
        begin
        {
            [void][System.Reflection.Assembly]::LoadWithPartialName("System.Security")
        }
    
        process 
        {
            switch ($pscmdlet.ParameterSetName) {
                "CertFile" {
                    try {
                        $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $($CertFile.FullName),$CertPassword
                    }
                    catch {   
                        Write-Error ("Error reading '$CertFile': $_ .") -ErrorAction:Continue
                    }
                }
                "Cert" {
    
                }
                default {
                    Write-Error "Missing parameter:`nYou need to specify either a certificate or a certificate file name."
                }
            }
    
            switch -regex ($storeType) {
                "Machine$" { $StoreScope = "LocalMachine" }
                "User$"  { $StoreScope = "CurrentUser" }
            } 
    
            if ( $Cert ) {
                $StoreNames | ForEach-Object {
                    $StoreName = $_
                    Write-Verbose " [Import-Certificate] :: $($Cert.Subject) ($($Cert.Thumbprint))"
                    Write-Verbose " [Import-Certificate] :: Import into cert:\$StoreScope\$StoreName"
    
                    if (Test-Path "cert:\$StoreScope\$StoreName") {
                        try
                        {
                            $store = New-Object System.Security.Cryptography.X509Certificates.X509Store $StoreName, $StoreScope
                            $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
                            $store.Add($Cert)
                            if ( $CertFile ) {
                                Write-Verbose " [Import-Certificate] :: Successfully added '$CertFile' to 'cert:\$StoreScope\$StoreName'."
                            } else {
                                Write-Verbose " [Import-Certificate] :: Successfully added '$($Cert.Subject) ($($Cert.Thumbprint))' to 'cert:\$StoreScope\$StoreName'."
                            }
                        }
                        catch
                        {
                            Write-Error ("Error adding '$($Cert.Subject) ($($Cert.Thumbprint))' to 'cert:\$StoreScope\$StoreName': $_ .") -ErrorAction:Continue
                        }
                        if ( $store ) {
                            $store.Close()
                        }
                    } 
                    else {
                        Write-Warning "Certificate store '$StoreName' does not exist. Skipping..."
                    }
                }
            } else {
                Write-Warning "No certificates found."
            }
        }
    
        end { 
            Write-Host "Finished importing certificates." 
        }
    }
    

    我这样成功使用了这些功能:

    ##Import self-signed certificate
    Get-WebsiteCertificate $baseUrl local.cer -trust | Out-Null
    Import-Certificate -certfile local.cer -SN Root  | Out-Null
    

    【讨论】:

    • 我试过Get-WebsiteCertificate,返回的对象只包括Issuer、Subject和一个无意义的句柄。是否有可能获得到期?编辑:回答自己。如果我使用-OutFile,然后将文件加载到 X509Certificate2 对象中,那么我会得到一整套信息,包括 NotAfter、DnsNameList 等。
    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 2021-05-21
    • 1970-01-01
    • 2012-03-17
    • 2015-11-15
    • 2017-10-15
    • 2020-08-06
    • 2018-04-10
    相关资源
    最近更新 更多