PKI安全框架之Certificate数字证书(二)——New-SelfSignedCertificate构建

概述

MakeCert:微软最早期的证书CLI工具,仅用于生成测试目的的X.509证书。‌它允许用户创建自签名证书,‌但有一些限制,‌例如,‌它仅适用于较旧的操作系统(win10 以前)版本,‌并且生成的证书可能不适合用于生产环境。‌makecert生成的证书私钥存储在.snk文件中,‌但这种方式不是最安全的,‌因为它以不受保护的方式存储私钥。‌因此,‌使用makecert时,‌需要特别注意私钥的安全保护。‌

感兴趣的朋友可参考

MakeCert - Win32 apps | Microsoft Learn

使用 MakeCert - Win32 apps | Microsoft Learn

Windows makecert生成代码签名证书-CSDN博客

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

 参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值