概述
MakeCert:微软最早期的证书CLI工具,仅用于生成测试目的的X.509证书。它允许用户创建自签名证书,但有一些限制,例如,它仅适用于较旧的操作系统(win10 以前)版本,并且生成的证书可能不适合用于生产环境。makecert生成的证书私钥存储在.snk文件中,但这种方式不是最安全的,因为它以不受保护的方式存储私钥。因此,使用makecert时,需要特别注意私钥的安全保护。
感兴趣的朋友可参考
MakeCert - Win32 apps | Microsoft Learn
New-SelfSignedCertificate
创建自定义签名证书。继MakeCert CLI改进工具(win10及以后版本),基于Cmdlet PSH环境。说实话,笔者翻烂了官方文档对该工具使用介绍挺粗糙的,一堆的坑准备好踩吧。
一、创建X509证书链
# PowerShell环境(以管理员身份运行)
# 默认存储位置:cert:LocalMachine\My【本地计算机\个人】
#准备条件
$pfxPassword = ConvertTo-SecureString -String "[pfx加密]" -Force -AsPlainText
$pfxFilePath = "[pfx文件路径]"
$cerFilePath = "[cer文件路径]"
# 语法结构
New-SelfSignedCertificate `
-Subject [使用者] `
-DnsName [使用者可选名称] `
-NotAfter (Get-Date).AddYears(20) `
-CertStoreLocation "cert:LocalMachine\My" ` #可选
-FriendlyName "[友好名称]" `
-HashAlgorithm SHA256 `
-KeyUsageProperty All `
-KeyUsage CertSign, CRLSign, DigitalSignature
-TextExtension @("2.5.29.19={text}CA=1&pathlength=1")
# 可缺省-Subject参数时,生成证书时默认取DnsName信息为[颁发给]者。
# 可缺省 -KeyAlgorithm和-KeyLength参数时,默认为RSA 2048。
# 可缺省 -NotBefore参数时,默认为从系统当前时间起始。
# 可缺省 -NotAfter参数时,生成证书时默认有效期为1年。
# 可缺省-FriendlyName参数时,生成证书时[友好名称]为空。
# 可缺省 -HashAlgorithm参数时,默认值SHA256。
# 可缺省 -KeyUsageProperty参数,指定私钥的键用法属性的键用法。默认值None。(使用底层KSP的默认值)
# 可选 -KeyUsage参数[密钥用法],指定在证书的密钥使用扩展名中设置的密钥用法。可接受的参数项:
# CertSign:证书签名
# CRLSign:CRL签名
# DataEncipherment:数据加密
# DecipherOnly
# DigitalSignature:数字签名
# EncipherOnly
# KeyAgreement
# KeyEncipherment:钥匙加密
# None:缺省时无
# NonRepudiation
# 必须 -TextExtension参数[目的用途],指定证书扩展数组为字符串,每个字符串必须采用OID对象标识符。
# 所有颁发的策略 (2.5.29.32.0)
# 客户端身份验证 (1.3.6.1.5.5.7.3.2)
# 服务器身份验证 (1.3.6.1.5.5.7.3.1)
# BitLocker驱动器加密 (1.3.6.1.4.1.311.67.1.1)
# 加密文档系统 (1.3.6.1.4.1.311.10.3.4)
# 文档签名 (1.3.6.1.4.1.311.10.3.12)
# 安全电子邮件 (1.3.6.1.5.5.7.3.4)
# 语法: TextExtension @(2.5.29.37={text}{oid},{oid})
# Example: TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
1、 Root根证书
根证书可以不需要DnsName [使用者可选名称(Web域名)],示例如下:
# Set certificate header info.
$Subject = "CN=Kingser Root for ps1"
$CertType = "Custom"
# Set certificate default export path local.
$ExportPath = "E:\Certificate\PSCert\"
# Root certificate generation
$rootCert = New-SelfSignedCertificate `
-Subject $Subject `
-Type $CertType `
-Keyusage None `
-NotAfter (Get-Date).AddYears(20).AddDays(-1) `
-FriendlyName "root Cert" `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-TextExtension @("2.5.29.19={text}CA=true")
# set certificate password here
$pfxPwd = ConvertTo-SecureString -String "Kissgh_" -Force -AsPlainText
# Export certificate to a file
$pfxfile = $ExportPath +"root.pfx"
$cerfile = $ExportPath +"root.cer"
Export-PfxCertificate -Cert $rootCert -FilePath $pfxfile -Password $pfxPwd
Export-Certificate -Cert $rootCert -FilePath $cerfile
# -KeySpec Signature 指定与新证书关联的私钥是否可用于签名、加密或两者兼而有之。 默认值None表示该cmdlet使用底层CSP的默认值
Type参数指定的是自定义证书类型,默认指SSLServerAuthentication类型。当Keyusage为None时,则密钥用法指的就是所有(用途)。
2、服务端证书
# Server certificate generation
$Subject = "CN=MesWebServer"
$serverCert = New-SelfSignedCertificate `
-Subject $Subject `
-DnsName "*.mes.com" `
-Signer $rootCert `
-NotAfter (Get-Date).AddYears(10).AddDays(-1) `
-FriendlyName "server Cert" `
-Type $CertType `
-Keyusage DigitalSignature, NonRepudiation, KeyEncipherment, CertSign `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.19={text}CA=false")
# Export certificate to a file
$pfxfile = $ExportPath +"server.pfx"
$cerfile = $ExportPath +"server.cer"
Export-PfxCertificate -Cert $serverCert -FilePath $pfxfile -Password $pfxPwd
Export-Certificate -Cert $serverCert -FilePath $cerfile
指定了Dns身份验证,此放在服务端证书。
3、客户端证书
# Client certificate generation
$Subject = "CN=MesWebClient"
$clientCert = New-SelfSignedCertificate `
-Subject $Subject `
-Signer $rootCert `
-NotAfter (Get-Date).AddYears(3).AddDays(-1) `
-FriendlyName "client Cert" `
-Type $CertType `
-Keyusage DigitalSignature, NonRepudiation, KeyEncipherment, CertSign `
-KeyExportPolicy Exportable `
-TextExtension @("2.5.29.19={text}CA=false")
# Export certificate to a file
$pfxfile = $ExportPath +"client.pfx"
$cerfile = $ExportPath +"client.cer"
Export-PfxCertificate -Cert $clientCert -FilePath $pfxfile -Password $pfxPwd
Export-Certificate -Cert $clientCert -FilePath $cerfile
终端实体证书一般需要明确密钥用途以及增强型扩展用途等,以最高程度提高证书的安全性。
4、证书部署及管理
#准备条件
$cerFilePath = "E:\Certificate\rootCert.cer"
# 导入Root根证书
Import-Certificate -FilePath $cerFilePath -CertStoreLocation Cert:\LocalMachine\Root
# Cert:\LocalMachine\Root是本地计算机根
# Cert:\CurrentUser\Root是当前用户根
# 检查并移除重复引用的证书
# 检查cert:\LocalMachine\My的重复的Root和CA证书,并移除
# 先检查出要移除的证书指纹码,然后通过Remove-Item进行移除。Remove-Item 参数-DeleteKey为连同私钥一并移除(慎用)
Get-ChildItem -Path cert:\LocalMachine\My
Remove-Item -Path cert:\LocalMachine\My\[指纹码]
# 可以通过检索DnsName值,进行移除
Get-ChildItem -Path cert:\LocalMachine\My -DnsName *xxx* | Remove-Item
二、题外话
对于PowerShell是可再编程性脚本,它能完全支持.NETFramework库的扩展开发。但感觉就是更新的比较慢,在此就举些例子,就当抛转引玉希望有大神也能分享一些相关案例。
# 通过证书指纹从指定存储位置读取证书
function Get-CertificateByThumbprint {
param (
[string]$thumbprint,
[string]$storeLocation = "CurrentUser",
[string]$storeName = "My"
)
# 获取指定存储位置和存储名称的X509Store对象
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store $storeName, $storeLocation
try {
# 打开存储
$store.Open("ReadOnly")
# 通过指纹查找证书
$cert = $store.Certificates.Find("FindByThumbprint", $thumbprint, $false)[0]
# 返回找到的证书对象
return $cert
} finally {
# 即使发生错误,确保在函数结束时关闭存储
$store.Close()
}
}
# 定义一个函数来查询指定的X509证书的私钥
function Get-CertificatePrivateKey {
param(
[Parameter(Mandatory=$true)]
[System.Security.Cryptography.X509Certificates.X509Certificate2]
$Certificate
)
# 获取证书的指纹
$certThumbprint = $Certificate.Thumbprint
# 获取当前用户的密钥容器
$keyContainers = Get-ChildItem -Path "Cert:\CurrentUser\My\$certThumbprint"
# 遍历密钥容器,查找与证书关联的私钥
foreach ($keyContainer in $keyContainers) {
try {
# 尝试打开私钥
$privateKey = $null
$privateKey = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($keyContainer)
if ($privateKey -ne $null) {
# 如果找到私钥,则输出
Write-Output "找到与证书关联的私钥。"
Write-Output $privateKey
break
}
}
catch {
# 如果出现异常,则忽略,继续查找
Write-Warning "无法访问私钥: $_"
}
}
}
$thumbprint = "EDA128819C204EE4C226AE3A0531E665DB244A1D"
$cert = Get-CertificateByThumbprint -thumbprint $thumbprint
Get-CertificatePrivateKey -Certificate $cert