【问题标题】:Generate Self-signed certificate with Root CA Signer使用 Root CA Signer 生成自签名证书
【发布时间】:2017-05-16 14:18:29
【问题描述】:

场景:我在 Windows Server 2012r2 上使用 PowerShell 生成根证书,并希望使用它在动态生成(和销毁)的开发/测试环境中签署新创建的中间证书和 Web 证书.这些脚本是远程部署的,目的是尽可能保持纯 PowerShell。在 Windows 10/2016 中,这在生成根证书后相对容易:

$Cert = New-SelfSignedCertificate -Signer $Root -Subject "CN=$Subject"

我已经使用 COM X509Enrollment.CX509CertificateRequestCertificateSecurity.Cryptography.X509Certificates.X509Certificate2 在我有一段时间的混账 PS 中生成了根证书,主要是因为我需要确保主题和用法设置得非常具体。我不太确定如何使用它来签署没有上述(我以前使用过)的标准证书。

有一些在 C# 中使用 Bouncy Castle(见下文)的示例,我可以将其绑定到 PowerShell,但是我需要在动态开发/测试环境中另外部署它,并且我希望能够在 Powershell 中执行此操作(如果需要,通过 COM)具有最少的依赖关系。

【问题讨论】:

  • 为什么不使用 Puppet 服务器的 CA?此外,证书要么是自签名的,要么是由 CA 签名的,而不是两者兼而有之。
  • 抱歉,我意识到我写了“CA”,这可能会造成混淆——我的意思是自签名根证书。我正在生成一个根证书并将根证书用作新证书的签名证书。显然,这仍然是自签名的,这就是我们的目标 - 在 2016 年这不是问题,我正在寻找接近 2012r2 Powershell 的纯解决方案。可能只是我被 Bouncy Castle 困住了。
  • 您可以使用makecert(要获得实用程序,请参阅here)。但是,为什么不为此目的使用 Puppet CA 呢?所有被管节点都已经有一个由它签名的主机证书。
  • 因为秒。团队不希望将其用于测试。不希望为我们的 IIS 和 API 双重使用 puppet 证书;或者让我争论用例(我宁愿使用我们的 CA 的 CSR)。他们对证书类型和用途有特定要求,因此我的要求是生成具有特定详细信息的根证书、中间证书和 Web 证书 - 使用根证书登录动态创建。至于 MakeCert,是的——我也知道 OpenSSL——但我问的是是否有类似于 2016 PoSh 的 2012 PoSh 特定解决方案以避免外部包依赖。
  • 我认为没有。我的建议是使用makecert 来满足您的目的。

标签: powershell sql-server-2012 windows-server-2012-r2


【解决方案1】:

在我的情况下,避免 makecert 和 openssl 的最终解决方案是使用 Powershell 和 BouncyCastle。我通过 RLipscombe 从PSBouncyCastle 分叉了 PSBouncyCastle 存储库,并将 1.8.1 Bouncy Castle 推入。我的分叉版本是我用于脚本的版本,分叉位于Forked: PSBouncyCastle.New

然后我以StackOverflow: C# Generate Certificates on the Fly为灵感,在下面编写了以下powershell,我将把它添加到我的GitHub并发表评论,我会尽快修改

Import-Module -Name PSBouncyCastle.New

function New-SelfSignedCertificate {
  [CmdletBinding()]
  param (
    [string]$SubjectName,
    [string]$FriendlyName = "New Certificate",
    [object]$Issuer,
    [bool]$IsCA = $false,
    [int]$KeyStrength = 2048,
    [int]$ValidYears = 2,
    [hashtable]$EKU = @{}
  )

  # Needed generators
  $random = New-SecureRandom
  $certificateGenerator = New-CertificateGenerator

  if($Issuer -ne $null -and $Issuer.HasPrivateKey -eq $true)
  {
    $IssuerName = $Issuer.IssuerName.Name
    $IssuerPrivateKey = $Issuer.PrivateKey
  }
  # Create and set a random certificate serial number
  $serial = New-SerialNumber -Random $random
  $certificateGenerator.SetSerialNumber($serial)

  # The signature algorithm
  $certificateGenerator.SetSignatureAlgorithm('SHA256WithRSA')

  # Basic Constraints - certificate is allowed to be used as intermediate.
  # Powershell requires either a $null or reassignment or it will return this from the function
  $certificateGenerator = Add-BasicConstraints -isCertificateAuthority $IsCA -certificateGenerator $certificateGenerator

  # Key Usage
  if($EKU.Count -gt 0) 
  {
    $certificateGenerator = $certificateGenerator | Add-ExtendedKeyUsage @EKU
  }
  # Create and set the Issuer and Subject name
  $subjectDN = New-X509Name -Name ($SubjectName)
  if($Issuer -ne $null) {
    $IssuerDN = New-X509Name -Name ($IssuerName)
  }
  else 
  {
    $IssuerDN = New-X509Name -Name ($SubjectName)
  }  
  $certificateGenerator.SetSubjectDN($subjectDN)
  $certificateGenerator.SetIssuerDN($IssuerDN)

  # Authority Key and Subject Identifier
  if($Issuer -ne $null)
  {
    $IssuerKeyPair = ConvertTo-BouncyCastleKeyPair -PrivateKey $IssuerPrivateKey
    $IssuerSerial = [Org.BouncyCastle.Math.BigInteger]$Issuer.GetSerialNumber()
    $authorityKeyIdentifier = New-AuthorityKeyIdentifier -name $Issuer.IssuerName.Name -publicKey $IssuerKeyPair.Public -serialNumber $IssuerSerial
    $certificateGenerator = Add-AuthorityKeyIdentifier -certificateGenerator $certificateGenerator -authorityKeyIdentifier $authorityKeyIdentifier
  }

  # Validity range of the certificate
  [DateTime]$notBefore = (Get-Date).AddDays(-1)
  if($ValidYears -gt 0) {
    [DateTime]$notAfter = $notBefore.AddYears($ValidYears)
  }
  $certificateGenerator.SetNotBefore($notBefore)
  $certificateGenerator.SetNotAfter($notAfter)


  # Subject public key ~and private
  $subjectKeyPair = New-KeyPair -Strength $keyStrength -Random $random
  if($IssuerPrivateKey -ne $null)
  {
    $IssuerKeyPair = [Org.BouncyCastle.Security.DotNetUtilities]::GetKeyPair($IssuerPrivateKey)
  }
  else 
  {
    $IssuerKeyPair = $subjectKeyPair
  }
  $certificateGenerator.SetPublicKey($subjectKeyPair.Public)

  # Create the Certificate
  $IssuerKeyPair = $subjectKeyPair
  $certificate = $certificateGenerator.Generate($IssuerKeyPair.Private, $random)
  # At this point you have the certificate and need to convert it and export, I return the private key for signing the next cert
  $pfxCertificate = ConvertFrom-BouncyCastleCertificate -certificate $certificate -subjectKeyPair $subjectKeyPair -friendlyName $FriendlyName
  return $pfxCertificate
}

此 powershell 的一些用法示例如下:

生成根 CA

$TestRootCA = New-SelfSignedCertificate -subjectName "CN=TestRootCA" -IsCA $true
Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx

生成标准自签名

$TestSS = New-SelfSignedCertificate -subjectName "CN=TestLocal"
Export-Certificate -Certificate $TestSS -OutputFile "TestLocal.pfx" -X509ContentType Pfx

生成证书,使用根证书签名

$TestRootCA = New-SelfSignedCertificate -subjectName "CN=TestRootCA" -IsCA $true
$TestSigned = New-SelfSignedCertificate -subjectName "CN=TestSignedByRoot" -issuer $TestRootCA

Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx
Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx

生成具有特定用途的自签名

$TestServerCert = New-SelfSignedCertificate -subjectName "CN=TestServerCert" -EKU @{ "ServerAuthentication" = $true }

请注意,-EKU 参数通过 splatting 接受,它这样做是为了确保添加到 Add-ExtendedKeyUsage 的任何内容都被有效传递。它接受以下证书用法:

  • 数字签名
  • 不可否认
  • 密钥加密
  • 数据加密
  • 密钥协议
  • KeyCertSign
  • CrlSign
  • 仅加密
  • 仅解密

这符合我的需要,并且似乎适用于我们用于动态环境的所有 Windows 平台。

【讨论】:

  • -IsCA-Issuer 不是 New-SelfSignedCertificate 的有效参数?
  • 我没看到,Is-CA 参数是库脚本 (New-SelfSignedCertEx) 的一部分,它不提供签名能力。需要将“root/Is-CA”和“Signer”放在一起。在 2012r2 上,此功能不可用; New-SelfSignedCertificate 仅适用于(是?)2016/Win10。 System.Security.Cryptography.X509Certificates 没有公开我看到的功能。用例范围很窄:生成一个自签名根,并使用它在 Server 2012r2 及更早版本上使用 Powershell(未绑定)签署其他 s.s.s 证书。
  • 啊,没看出问题是关于 Server 2012 的。
  • 感谢您的回复 - 非常有帮助。有没有办法在不创建 CA 的情况下使用根 CA 签署证书?例如,如果我想重用现有的 CA。谢谢!
  • 嘿@Jake - 取决于 Powershell 的版本以及您加载证书的方式。如果它已经存在于您的证书存储中,那么就像使用 Get-ChildItem -path cert:\* 并将该星号更改为正确的路径或按主题名称等过滤一样简单。Get Certs 在 Powershell 6 中,您可以使用 Get-PfxCertificate from a file
【解决方案2】:

简单地这样做怎么样:

$cert = New-SelfSignedCertificate -FriendlyName "MyCA"
      -KeyExportPolicy ExportableEncrypted 
      -Provider "Microsoft Strong Cryptographic Provider" 
      -Subject "SN=TestRootCA" -NotAfter (Get-Date).AddYears($ExpiryInYears) 
      -CertStoreLocation Cert:\LocalMachine\My -KeyUsageProperty All 
      -KeyUsage CertSign, CRLSign, DigitalSignature

重要的参数是-KeyUsageProperty-KeyUsage

【讨论】:

  • 您好,感谢您的光临!请参阅对已接受答案的第二条评论以及请求的第一句话。对于 Server 2012r2 及更早版本,此功能未在 New-SelfSignedCertificate 中公开。 New-SelfSignedCertificate old New-SelfSignedCertificate new 这就是问题的确切原因。
  • 我的错!有时我的速读太过分了!这当然解释了推荐的答案!
【解决方案3】:

“Itiverba 自签名证书生成器”(http://www.itiverba.com/en/software/itisscg.php) 是一款适用于 Windows 的免费 G​​UI 工具,可让您创建自己的 CA 证书并使用它签署最终证书。您可以以 PEM、CER、DER、PFX 文件格式导出证书。

编码只需 3 行:
主题:CN="Testcorp - Private CA"
基本约束:V(选中)
基本约束/主题类型:CA

提供文件名并选择文件格式,然后单击“创建证书”按钮。您的自定义 CA 证书已完成。

【讨论】:

  • 感谢您的回复,但我正在寻找一种 Powershell 方法来在脚本进程中执行此操作;这有那个选项吗?它似乎没有。
【解决方案4】:

创建根证书的简单方法是执行以下操作。请注意确保证书是根证书的文本扩展名。此类证书必须放置在 证书存储中以表明信任。例如。 'cert:\LocalMachine\My' 存储。

确保 KeyUsage 是您想要的。这当然可以改变,但微软并不擅长记录为什么你应该按照他们的建议去做。

证书的移动/复制必须通过导出证书并再次导入来完成。或者在正确的位置创建证书。请注意,一般情况下,证书只会在我的商店中创建。 Certificate Provider PowerShell functions 中描述了一些支持命令。

证书默认是可导出的。

$rootCert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My `
            -DnsName "RootCA" `
            -TextExtension @("2.5.29.19={text}CA=true") `
            -KeyUsage CertSign,CrlSign,DigitalSignature;

代码取自https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-create-temporary-certificates-for-use-during-development

【讨论】:

  • 您好!感谢您的回答,但此评论与 2012r2 Powershell 相关,特别是根据第一句和之前的答案 cmets。在 2012r2 及之前的版本中,PowerShell 仅具有以下参数:-DnsName、-CloneCert、-CertStoreLocation、-WhatIf、-Confirm。这意味着接受的答案(我自己的)仍然是最正确的 AFAIK。
猜你喜欢
  • 2010-10-30
  • 2020-07-30
  • 2019-04-18
  • 1970-01-01
  • 2012-08-29
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多