- Example usage
- Function
- Get-certificate testing
- How to download the ssl certificate from a website using powershell?
- Walk through
- What the function does
- Поиск информации в нашем сертификате
- Резюме
- Сертификат защиты документов
- Сертификат подписи кода
- Создание самоподписанного сертификата
- Создание самоподписанного сертификата средствами powershell – pki extensions
Example usage
- offline mode to create a certificate request with a single name (Subject only)
Function
[sourcecode language=”powershell”]function New-CertificateRequest {param ([Parameter(Mandatory=$true, HelpMessage = “Please enter the subject beginning with CN=”)][ValidatePattern(“CN=”)][string]$subject,[Parameter(Mandatory=$false, HelpMessage = “Please enter the SAN domains as a comma separated list”)
][array]$SANs,[Parameter(Mandatory=$false, HelpMessage = “Please enter the Online Certificate Authority”)][string]$OnlineCA,[Parameter(Mandatory=$false, HelpMessage = “Please enter the Online Certificate Authority”)][string]$CATemplate = “WebServer”)
### Preparation$subjectDomain = $subject.split(‘,’)[0].split(‘=’)[1]if ($subjectDomain -match “*.”) {$subjectDomain = $subjectDomain -replace “*”, “star”}$CertificateINI = “$subjectDomain.ini”$CertificateREQ = “$subjectDomain.req”$CertificateRSP = “$subjectDomain.rsp”$CertificateCER = “$subjectDomain.cer”
### INI file generationnew-item -type file $CertificateINI -forceadd-content $CertificateINI ‘[Version]’add-content $CertificateINI ‘Signature=”$Windows NT$”’add-content $CertificateINI ”add-content $CertificateINI ‘[NewRequest]’$temp = ‘Subject=”’ $subject ‘”’add-content $CertificateINI $tempadd-content $CertificateINI ‘Exportable=TRUE’add-content $CertificateINI ‘KeyLength=2048’add-content $CertificateINI ‘KeySpec=1’add-content $CertificateINI ‘KeyUsage=0xA0’add-content $CertificateINI ‘MachineKeySet=True’add-content $CertificateINI ‘ProviderName=”Microsoft RSA SChannel Cryptographic Provider”’add-content $CertificateINI ‘ProviderType=12’add-content $CertificateINI ‘SMIME=FALSE’add-content $CertificateINI ‘RequestType=PKCS10’add-content $CertificateINI ‘[Strings]’add-content $CertificateINI ‘szOID_ENHANCED_KEY_USAGE = “2.5.29.
37″’add-content $CertificateINI ‘szOID_PKIX_KP_SERVER_AUTH = “1.3.6.1.5.5.7.3.1”’add-content $CertificateINI ‘szOID_PKIX_KP_CLIENT_AUTH = “1.3.6.1.5.5.7.3.2”’if ($SANs) {add-content $CertificateINI ‘szOID_SUBJECT_ALT_NAME2 = “2.5.29.17”’add-content $CertificateINI ‘[Extensions]’add-content $CertificateINI ‘2.5.29.17 = “{text}”’
foreach ($SAN in $SANs) {$temp = ‘_continue_ = “dns=’ $SAN ‘&”’add-content $CertificateINI $temp}}
### Certificate request generationif (test-path $CertificateREQ) {del $CertificateREQ}certreq -new $CertificateINI $CertificateREQ
### Online certificate request and importif ($OnlineCA) {if (test-path $CertificateCER) {del $CertificateCER}if (test-path $CertificateRSP) {del $CertificateRSP}certreq -submit -attrib “CertificateTemplate:$CATemplate” -config $OnlineCA $CertificateREQ $CertificateCER
certreq -accept $CertificateCER}}[/sourcecode]
Get-certificate testing
I wanted this to use default PowerShell features and not depend on any custom modules. Get-Certificate introduced with Windows 2021 looked promising but seems to be designed for computer and personal certificate requests. I encountered a few problems:
How to download the ssl certificate from a website using powershell?
You should be able to get the public key by using the ServicePoint property on the HttpWebRequest object. This necessary information will be populated once we have made a http request to the site in question.
If the request is made to a site which has an untrusted certificate the GetResponse method will throw an exception, However, the ServicePoint will still contain the Certificate so we want to ensure we ignore WebException if the status is a trust failure.
So something like the following should work:
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"
If you want to call the method many times and some might have the same address, you might want to improve the function by using the ServicePointManager.FindServicePoint(System.Uri) method, since it will return a cached version if a request has already been made to that site. So you could check if the service point has been populated with information. If it hasn’t, make the web request. If it has, just use the already existing information, saving yourself an http request.
Walk through
The function takes 1 mandatory parameter and 3 additional parameters:
Based on the subject name (excluding ‘CN=’) the certificate request .ini file, request file, response file and certificate file are generated. A new .ini file is created using a basic template depending on whether a single name certificate or SANs are specified and written to disk.
Example of a single name certificate request .ini
[sourcecode language=”powershell”][Version]Signature=”$Windows NT$”
What the function does
The function I created has been tested on Windows 2008 R2, Windows 2021 and Windows 2021 R2 Preview, although it should work on any computer with PowerShell 2.0 or later (version 1 not tested) that supports certreq.exe. I am using a function instead of a script as I think it can easily be dropped into other scripts without creating further dependencies. To satisfy the requirements I had, the script can be used in the following ways:
- offline mode to create a certificate request with a single name (Subject only)
- offline mode to create a certificate request with SANs
- online mode to create a certificate request with a single name, request a certificate directly from a Windows Enterprise Certificate Authority and import the certificate
- online mode to create a certificate request with SANs, request a certificate directly from a Windows Enterprise Certificate Authority and import the certificate
The certificates created are exportable and contain the private key.
Поиск информации в нашем сертификате
Давайте удостоверимся, что сертификат был создан так, как мы ожидали. Чтобы найти информацию о конкретном сертификате с PowerShell, вы можете использовать Get-ChildItem Командлет, как вы могли бы перечислить файлы в каталоге.
Резюме
PowerShell делает создание самозаверяющих сертификатов невероятно простым. Эти сертификаты имеют множество применений, но важно помнить, что их следует использовать только при тестировании. У вас не будет действительной цепочки доверия сертификатов для проверки ваших самозаверяющих сертификатов.
Видя, насколько быстро и легко создавать самозаверяющие сертификаты, вы можете начать делать это сегодня и правильно шифровать любые соединения или данные, которые вам нужны!
Просмотры:228
Сертификат защиты документов
Возможно, раньше вы с этим не сталкивались, но PowerShell с API защиты данных может шифровать файлы в вашей системе с помощью сертификата защиты документов. Используя New-SelfSignedCertificate Командлет, мы можем легко сделать сертификат для шифрования ваших документов.
Сертификат подписи кода
Если вы работаете в PowerShell, вы узнаете о политика исполнения, Если у вас установлена политика выполнения AllSigned тогда вам нужно будет подписать каждый скрипт, который работает в вашей системе. Чтобы создать сертификат, сделать это довольно просто!
PS C:> New-SelfSignedCertificate -Type 'CodeSigningCert' -DnsName 'MyHost'
PSParentPath: Microsoft.PowerShell.SecurityCertificate::LocalMachineMY
Thumbprint Subject EnhancedKeyUsageList
---------- ------- --------------------
14D535EG834370293BA103159EB00876A79959D8 CN=MyHost Code SigningСоздание самоподписанного сертификата
Чтобы создать самозаверяющий сертификат с помощью PowerShell, вы можете использовать New-SelfSignedCertificate Командлет. Этот командлет включен в PKI модуль.
Существует много вариантов создания сертификатов. Общие самозаверяющие типы сертификатов SSLServerAuthentication (по умолчанию для командлета) и CodeSigning, Также вы можете создать DocumentEncryptionCert, что очень полезно для шифрования файлов, и, наконец, Custom сертификат, который позволяет вам указать множество пользовательских параметров.
Давайте идти вперед и создать регулярный SSLServerAuthentication сертификат. Это тот, который обычно используется для защиты сайтов с шифрованием SSL. Вы можете увидеть пример этого ниже. В этом примере сертификат хранится в Cert:LocalMachineMy Certificate Store,
Создание самоподписанного сертификата средствами powershell – pki extensions
Самоподписанные сертификаты — это зло, за исключением сертификатов корневых CA. Я об этом говорил, говорю и буду говорить. Но в данном случае мы не преследуем цель создания самоподписанного сертификата. Нас по сути будет интересовать немного другое — рассмотрение принципа, который заложен во многих популярных тулзах как MakeCert или OpenSSL. Лично я не фанат ни первого, ни второго по своим сугубо личным причинам. Но, кроме этих двоих есть ещё утилита CertReq.exe, которая достаточно православная и вряд ли ей грозит вымирание (а жаль). Вобщем, сегодня предлагаю ещё раз поковырять CryptoAPI.
Как мы уже знаем, CryptoAPI обладает большим количеством всяческих COM интерфейсов, при помощи которых мы можем работать практически с любыми аспектами цифровых сертификатов. Некоторые из них бажные, а некоторые — не очень :-), но функционал у них впечатляющий. В настоящее время существует 2 основных набора API, которые реализуют клиентскую часть энроллмента — XEnroll и CertEnroll. Первый доступен только в системах начиная с Windows 2000 и до Windows Server 2003 включительно. В более новых версиях XEnroll был вырезан вместе с CAPICOM’ом полностью (куски CAPICOM’а ещё можно найти в висте) за ненадобностью. Семейство интерфейсов CertEnroll было значительно переработано и расширено, что делает его крайне гибким. Я не буду рассказывать про XEnroll, потому что это неинтересно и трупов пинать нехорошо.
Многие считают, что CryptoAPI — это очень сложно. Я могу возразить им. Я не программист совсем, но могу достаточно свободно их использовать. Нашей отправной точкой будет MSDN по адресу: Certificate Enrollment API Reference. Эта секция содержит всё самое необходимое — описание интерфейсов и перечисления. И самый первый интерфейс, который мы видим — IX509Enrollment. Этот интерфейс реализует нечто промежуточное между клиентом и сервером. Мы можем по описанию найти то, что нам нужно, а именно первую секцию — Out-of-band-enrollment. И мы видим, что для него надо сначала вызвать метод CreateRequest(). Но прежде чем вызывать метод, нам надо создать форму сертификата, на основе которой будет создан запрос. Как я уже упоминал, мы будем делать самоподписанный сертификат, поэтому следующий интерфейс подойдёт нам как нельзя кстати — IX509CertificateRequestCertificate2. Вот давайте с него и начнём.
Все указанные здесь и далее интерфейсы являются COM интерфейсами семейства X509Enrollment и эти объекты создаются следующим образом:
$Cert=New-Object-ComObjectX509Enrollment.CX509CertificateRequestCertificate.1
Примечание: как строятся такие команды? Поскольку это COM интерфейс, первую букву I в названии интерфейса меняем на букву C. Далее, если мы видим цифру 2 в конце названия интерфейса, в команде мы ставим точку и пишем число на единцу меньшее. Вот такие нехитрые правила.
Прежде чем его начать использовать, нам надо инициализировать его. К сожалению документация на MSDN далеко не полная, поэтому будем искать нужные методы через PowerShell и командлет Get-Member:
[↓] [vPodans] $cert | gm -MemberType methods TypeName: System.__ComObject#{728ab35a-217d-11da-b2a4-000e7bbb2b09} Name MemberType Definition ---- ---------- ---------- CheckPublicKeySignature Method void CheckPublicKeySignature (IX509PublicKey) CheckSignature Method void CheckSignature (Pkcs10AllowedSignatureTypes) Encode Method void Encode () GetCspStatuses Method ICspStatuses GetCspStatuses (X509KeySpec) GetInnerRequest Method IX509CertificateRequest GetInnerRequest (InnerRequestLevel) Initialize Method void Initialize (X509CertificateEnrollmentContext) InitializeDecode Method void InitializeDecode (string, EncodingType) InitializeFromCertificate Method void InitializeFromCertificate (X509CertificateEnrollmentContext, string... InitializeFromPrivateKey Method void InitializeFromPrivateKey (X509CertificateEnrollmentContext, IX509Pr... InitializeFromPrivateKeyTemplate Method void InitializeFromPrivateKeyTemplate (X509CertificateEnrollmentContext,... InitializeFromPublicKey Method void InitializeFromPublicKey (X509CertificateEnrollmentContext, IX509Pub... InitializeFromTemplate Method void InitializeFromTemplate (X509CertificateEnrollmentContext, IX509Enro... InitializeFromTemplateName Method void InitializeFromTemplateName (X509CertificateEnrollmentContext, string) IsSmartCard Method bool IsSmartCard () ResetForEncode Method void ResetForEncode () [↓] [vPodans]
Из всех методов нам по сути доступен только InitializeFromPrivateKey(), поскольку остальные методы инициализации требуют наличие доступа к Certification Authority. Посмотрим что требуется для этого метода:
[↓] [vPodans] $cert | gm -MemberType methods | ?{$_.name -eq "InitializeFromPrivateKey"} | select definition Definition ---------- void InitializeFromPrivateKey (X509CertificateEnrollmentContext, IX509PrivateKey, string) [↓] [vPodans]
В качестве аргументов метода нам надо указать контекст энроллмента и объект закрытого ключа. Значения контекста находятся здесь: X509CertificateEnrollmentContext (просто включаете поиск на MSDN по названию перечисления). В качестве контекста мы можем выбрать контекст текущего пользователя или компьютера (остальное нас сейчас не волнует совсем). Контекст пользователя имеет значение 0x1. Так и запишем. Но этого мало. Надо ещё создать объект закрытого ключа:
$PrivateKey=New-Object-ComObjectX509Enrollment.CX509PrivateKey
Этот интерфейс позволяет задавать различные параметры закрытого ключа, но мы обойдёмся лишь самым необходимым:
$PrivateKey.ProviderName="Microsoft Base Cryptographic Provider v1.0"$PrivateKey.KeySpec=0x2$PrivateKey.Length=1024$PrivateKey.MachineContext=0x0$PrivateKey.Create()
Ура! Мы сгенерировали ключ. Теперь вернёмся к предыдущему интерфейсу и инициализируем его из закрытого ключа:
$Cert.InitializeFromPrivateKey(0x1,$PrivateKey,"")
Мы указываем контекст текущего пользователя и объект закрытого ключа. Там есть ещё один аргумент, который называется String. Я не знаю, что они этим хотели сказать, поэтому оставляем пустую строку. А теперь вернёмся к интерфейсу IX509CertificateRequestCertificate2 и посмотрим, что мы можем сделать сейчас. Например, используя свойства NotBefore и NotAfter мы зададим срок действия сертификата. Например, 1 год с сегодняшнего дня:
$Cert.NotBefore=[datetime]::Now$Cert.NotAfter=$Cert.NotBefore.AddDays(365)
Теперь нам надо добавить следующие свойства: EncancedKeyUsage (т.е. для каких целей вообще будет использоваться сертификат), Subject (на кого будет выписан сертификат) и Issuer (кто выдал этот сертификат). Поскольку у нас самоподписанный сертификат, поле Subject и Issuer будут одинаковые. На MSDN’е не хватает документации по свойствам Issuer и Subject, но у нас есть поиск, который нас приведёт сюда: IX500DistinguishedName. Поля Subject и Issuer должны заполняться в формате Distinguished Name и доступные префиксы для DN достаточно понятно расписаны в таблице. Нам нужно как-то активировать этот объект. Методов для инициализации здесь нет, поэтому будем использовать метод Encode().
Лирическое отступление: в подавляющем большинстве случаев вы не можете присваивать значения свойствам объектов после создания самих объектов. Предварительно их надо «активировать» одним из двух способов. Если у объекта есть метод Initialize или производное от него, необходимо сначала воспользоваться одним из доступных методов инициализации. Если объект не содержит явных методов инициализации, нужно воспользоваться методом Encode, который кодирует объект или строку в ASN.1 DER строку и инициализирует объект. Единственным исключением из этого правила являются коллекции объектов. Они как правило используют метод Add() для добавления уже инициализированных объектов.
Уже с главной страницы IX500DistinguishedName видно, что Encode кодирует строку, которая записана в DN формате. Поэтому вызываем этот метод:
$SubjectDN.Encode("CN=Some Subject,DC=lucernepublishing,DC=COM",0x0)
После строки нужно ещё указать флаг, в котором указана строка DN. Ставим дефолтный флаг. Теперь у нас готово поле Subject и Issuer (как мы договаривались, они будут одинаковые). Давайте их прицепим к нашему шаблону сертификата:
$Cert.Subject=$SubjectDN$Cert.Issuer=$Cert.Subject
Что нам осталось сделать? Нам надо создать расширение Enchanced Key Usage. Для этого нам надо использовать следующий интерфейс: IX509ExtensionEnhancedKeyUsage:
$EKU=New-Object-ComObjectX509Enrollment.CX509ExtensionEnhancedKeyUsage
Данный объект инициализируется из коллекции объектов IObjectIds. Давайте создадим эту коллекцию:
$OIDs=New-Object-ComObjectX509Enrollment.CObjectIDs
В эту коллекцию с использованием метода Add() надо добавить один или несколько объектов IObjectId, каждый из которых представляет конкретное предназначение сертификата. Например, Server Authentication, Client Authentication, Smart Card Logon, Secure e-mail и т.д. Но мы сделаем сертификат для Code Signing. OID этого EKU = 1.3.6.1.5.5.7.3.3. Вот и сделаем его:
$OID=New-Object-ComObjectX509Enrollment.CObjectID$OID.InitializeFromValue("1.3.6.1.5.5.7.3.3")$OIDs.Add($OID)$EKU.InitializeEncode($OIDs)
объект EKU у нас готов, теперь его надо добавить в наш шаблон сертификата. Поскольку это не стандартное поле сертификата, а расширение, добавляем этот объект в свойство X509Extensions, которое является аналогом интерфейса IX509Extensions и, который в свою очередь, является коллекцией расширений. Поэтому добавляем наше расширение методом Add():
$Cert.X509Extensions.Add($EKU)
Всё, мы собрали все минимально необходимые поля и расширения:
[↓] [vPodans] $cert Type : 4 EnrollmentContext : 1 Silent : False ParentWindow : UIContextMessage : SuppressDefaults : False ClientId : CspInformations : System.__ComObject HashAlgorithm : System.__ComObject AlternateSignatureAlgorithm : False TemplateObjectId : PublicKey : System.__ComObject PrivateKey : System.__ComObject NullSigned : False ReuseKey : False Subject : System.__ComObject CspStatuses : System.__ComObject SmimeCapabilities : False SignatureInformation : System.__ComObject KeyContainerNamePrefix : lp CryptAttributes : X509Extensions : System.__ComObject CriticalExtensions : System.__ComObject SuppressOids : System.__ComObject Issuer : System.__ComObject NotBefore : 16.04.2021 18:25:22 NotAfter : 16.04.2021 18:25:22 SignerCertificate : PolicyServer : Template : [↓] [vPodans]
Теперь мы можем превращать наш шаблон сертификата в настоящй сертификат.
Лирическое отступление: а что такое запрос в техническом смысле? На самом деле запрос ничем не отличается от сертификата. Когда вы запрашиваете сертификат у CA, клиент использует эти же интерфейсы для генерации запроса. При этом получается самый настоящий самоподписанный сертификат, где Subject и Issuer одинаковые и равны имени текущего пользователя или компьютера, а так же содержит все необходимые расширения. Сам запрос подписывается закрытым ключом, который мы сгенерировали. По большому счёту, его уже можно использовать как настоящий самоподписанный сертификат. Если его отправить на сервер CA, то последний просто подменяет значения необходимых полей (как Issuer, в котором он ставит себя) и расширений, удаляет старую подпись и подписывает сертификат новой подписью. Вы можете убедиться в этом очень просто. Сгенерируйте запрос для сертификата, откройте оснастку Certificates и разверните секцию Certificate Enrollment Requests. Там будет этот самый запрос в виде уже готового сертификата. Просто там он ждёт, пока какой-нибудь CA не подпишет его.
Давайте вернёмся в самое начало текущего поста и вспомним про «исходный предмет» — IX509Enrollment. Вот этот интерфейс нам сконвертирует шаблон сертификата в настоящий сертификат с использованием метода CreateRequest(). Но прежде чем использовать метод, нам надо инициализировать объект:
$Request=New-Object-ComObjectX509Enrollment.CX509enrollment$Request.InitializeFromRequest($Cert)
И генерируем файл запроса, который ничем не отличается от самоподписанного сертификата:
$endCert=$Request.CreateRequest(0x0)
В аргументах метода указываем кодировку согласно этой страничке: EncodingType Enumeration. Мы выбираем Base64 с заголовками. $endCert будет содержать сам сертификат (открытую его часть). Фактически запрос хранится в контейнере Certificate Enrollment Requests. Поскольку этот интерфейс не был задуман специально для самоподписанных сертификатов мы проходим стандартную процедуру установки сертификата. Мы просто берём открытую часть нашего же сертификата и устанавливаем её. Вот, кстати, как он выглядит:
[↓] [vPodans] $endcert -----BEGIN CERTIFICATE----- MIICaTCCAdKgAwIBAgIQEzCS/mFIxLBAiGjz7 n0dDANBgkqhkiG9w0BAQUFADBP MRMwEQYKCZImiZPyLGQBGRYDQ09NMSEwHwYKCZImiZPyLGQBGRYRbHVjZXJuZXB1 Ymxpc2hpbmcxFTATBgNVBAMMDFNvbWUgU3ViamVjdDAeFw0xMDA0MTgxMTI5MDla Fw0xMTA0MTgxMTI5MDlaME8xEzARBgoJkiaJk/IsZAEZFgNDT00xITAfBgoJkiaJ k/IsZAEZFhFsdWNlcm5lcHVibGlzaGluZzEVMBMGA1UEAwwMU29tZSBTdWJqZWN0 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBGa PnrhnOFO5 76c5zX5/ xh Kb2hUYl/pRuIKzYcqrmkvqjpPK/McusibT1h70emUkED0TSZsAlSivdIFK6WSxn6 HsTCaGIHhyOSKAvzQkBsZ74BPEydGT5LiX0 MOTyxwFAHhb bqfbkdkXqUSkJAHK Z6p fgX8uaJkKjL/kwIDAQABo0YwRDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNV HQ4EFgQUzIFwoRTY6KjUiqmjWjSjlkxbNncwDgYDVR0PAQH/BAQDAgeAMA0GCSqG SIb3DQEBBQUAA4GBACizodCpl/cF3OGLUx8HVag0yhr1e1P8 CLPc31FmCPAY1CO T0yxyJPoafkbXKRjclevNJdvxE3ys9fyYigFUhgswh3oWmjanDaatPKa0kE4147k SQHvN8JP20KeDDCJBk/FbS3xCn3jTix90ddzTa1uFoqBbBNbKOaDHIrqypTY -----END CERTIFICATE----- [↓] [vPodans]
Система приклеит этот сертификат к шаблону сертификата и переложит его уже в контейнер Personal:
$Request.InstallResponse(0x2,$endCert,0x0,"")
Всё, теперь мы увидим этот сертификат в нашем хранилище и который готов к использованию. Я немного переработал код и обернул его в красивую функцию, которая будет делать следующее:
- Генерировать тестовый самоподписанный сертификат для подписи скриптов PowerShell
- Устанавливать сертификат с закрытым ключом в контейнер Personal
- Устанавливать открытую часть сертификата в Trusted Root CAs для обеспечения доверия этому сертификату
- Устанавливать открытую часть сертификата в Trusted Publishers для задания явного доверия цифровым подписям, сделанные этим сертификатом.
functionNew-SigningCert{[CmdletBinding()]param([string]$Subject="CN=PowerShell User, OU=Test Signing Cert",[int][ValidateSet("1024","2048")]$KeyLength=1024,[datetime]$NotBefore=[DateTime]::Now,[datetime]$NotAfter=$NotBefore.AddDays(365),[switch]$Force)$OS=(Get-WmiObjectWin32_OperatingSystem).Versionif($OS[0]-lt6){Write-Warning"Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!"return}$SubjectDN=New-Object-ComObjectX509Enrollment.CX500DistinguishedName$SubjectDN.Encode($Subject,0x0)$OID=New-Object-ComObjectX509Enrollment.CObjectID$OID.InitializeFromValue("1.3.6.1.5.5.7.3.3")$OIDs=New-Object-ComObjectX509Enrollment.CObjectIDs$OIDs.Add($OID)$EKU=New-Object-ComObjectX509Enrollment.CX509ExtensionEnhancedKeyUsage$EKU.InitializeEncode($OIDs)$PrivateKey=New-Object-ComObjectX509Enrollment.CX509PrivateKey$PrivateKey.ProviderName="Microsoft Base Cryptographic Provider v1.0"$PrivateKey.KeySpec=0x2$PrivateKey.Length=$KeyLength$PrivateKey.MachineContext=0x0$PrivateKey.Create()$Cert=New-Object-ComObjectX509Enrollment.CX509CertificateRequestCertificate$Cert.InitializeFromPrivateKey(0x1,$PrivateKey,"")$Cert.Subject=$SubjectDN$Cert.Issuer=$Cert.Subject$Cert.NotBefore=$NotBefore$Cert.NotAfter=$NotAfter$Cert.X509Extensions.Add($EKU)$Cert.Encode()$Request=New-Object-ComObjectX509Enrollment.CX509enrollment$Request.InitializeFromRequest($Cert)$endCert=$Request.CreateRequest(0x1)$Request.InstallResponse(0x2,$endCert,0x1,"")if($Force){[Byte[]]$bytes=[System.Convert]::FromBase64String($endCert)foreach($Containerin"Root","TrustedPublisher"){$x509store=New-ObjectSecurity.Cryptography.X509Certificates.X509Store$Container,"CurrentUser"$x509store.Open([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)$x509store.Add([Security.Cryptography.X509Certificates.X509Certificate2]$bytes)$x509store.Close()}}}
С виду кажется сложно, но на самом деле тут ничего сложного нет совсем. Просто представьте себе сертификат как большую матрёшку, в которую вы вкладываете другие маленькие матрёшки, которые представляют собой поля и расширения сертификатов. Начинаете собирать самые маленькие матрёшки, вкладываете в более большие и в конечном итоге собираете настоящий сертификат. Хоть документация на MSDN не очень полная, используя командлет Get-Member вы можете восполнить этот пробел.
![]()
1
PS1 file
13.1 KB
New-SigningCert
