Hello folks, today I want to present you my another product in PKI integration with Windows PowerShell. I worked hard on server-side extensions: PowerShell PKI Module, which is (so far) the biggest project I have developed.

Now I got a time to work on client side extensions. Some prototypes are already published in this blog. The first complete tool (which is a part of client-side extensions) is self-signed certificate creation for testing purposes. The reason why I developed this tool is that makecert.exe (from Windows SDK) is now deprecated. The blog post provides a replacement for makecert — certreq.exe tool. Although, certreq is very cool, there are few things to note:

  1. certreq uses external INF file which may be a bit complicated.
  2. if there is a mistake in the INF file, certreq raises exception message box. It is a pain when the message box is raised in PowerShell remoting session. You never will see it and unable to close it!

My script relies on the same APIs as certreq and more flexible. Also it demonstrates the techniques of CertEnroll API usage in action.

The script defines the following parameters:

  • Subject — specifies the certificate subject in a X500 distinguished name format. Example: CN=Test Cert, OU=Sandbox
  • NotBefore — Specifies the date and time when the certificate become valid. By default previous day date is used.
  • NotAfter — Specifies the date and time when the certificate expires. By default, the certificate is valid for 1 year.
  • SerialNumber — Specifies the desired serial number in a hex format. Example: 01a4ff2
  • ProviderName — Specifies the Cryptography Service Provider (CSP) name. You can use either legacy CSP and Key Storage Providers (KSP). By default "Microsoft Enhanced Cryptographic Provider v1.0" CSP is used.
  • AlgorithmName — Specifies the public key algorithm. By default RSA algorithm is used. RSA is the only algorithm supported by legacy CSPs. With key storage providers (KSP) you can use CNG algorithms, like ECDH. For CNG algorithms you must use full name:
    ECDH_P256
    ECDH_P384
    ECDH_P521


    In addition, KeyLength parameter must be specified explicitly when non-RSA algorithm is used.
  • KeyLength — Specifies the key length to generate. By default 2048-bit key is generated.
  • KeySpec — Specifies the public key operations type. The possible values are: Exchange and Signature. Default value is Exchange.
  • EnhancedKeyUsage — Specifies the intended uses of the public key contained in a certificate. You can specify either, EKU friendly name (for example 'Server Authentication') or object identifier (OID) value (for example '1.3.6.1.5.5.7.3.1').
  • KeyUsage — Specifies restrictions on the operations that can be performed by the public key contained in the certificate. Possible values (and their respective integer values to make bitwise operations) are:
    EncipherOnly
    CrlSign
    KeyCertSign
    KeyAgreement
    DataEncipherment
    KeyEncipherment
    NonRepudiation
    DigitalSignature
    DecipherOnly


    you can combine key usages values by using bitwise OR operation. when combining multiple flags, they must be enclosed in quotes and separated by a comma character. For example, to combine KeyEncipherment and DigitalSignature flags you should type: "KeyEncipherment, DigitalSignature".

    If the certificate is CA certificate (see IsCA parameter), key usages extension is generated automatically with the following key usages: Certificate Signing, Off-line CRL Signing, CRL Signing.
  • SubjectAlternativeName — Specifies alternative names for the subject. Unlike Subject field, this extension allows to specify more than one name. Also, multiple types of alternative names are supported. The cmdlet supports the following SAN types:
    RFC822 Name
    IP address (both, IPv4 and IPv6)
    Guid
    Directory name
    DNS name
  • IsCA — Specifies whether the certificate is CA (IsCA = $true) or end entity (IsCA = $false) certificate. If this parameter is set to $false, PathLength parameter is ignored. Basic Constraints extension is marked as critical.

  • PathLength — Specifies the number of additional CA certificates in the chain under this certificate. If PathLength parameter is set to zero, then no additional (subordinate) CA certificates are permitted under this CA.

  • CustomExtension — Specifies the custom extension to include to a self-signed certificate. This parameter must not be used to specify the extension that is supported via other parameters. In order to use this parameter, the extension must be formed in a collection of initialized X509Extension objects.

  • SignatureAlgorithm — Specifies signature algorithm used to sign the certificate. By default 'SHA1' algorithm is used.

  • FriendlyName — Specifies friendly name for the certificate.

  • StoreLocation — Specifies the store location to store self-signed certificate. Possible values are: 'CurrentUser' and 'LocalMachine'. 'CurrentUser' store is intended for user certificates and computer (as well as CA) certificates must be stored in 'LocalMachine' store.

  • StoreName — Specifies the container name in the certificate store. Possible container names are:
    AddressBook
    AuthRoot
    CertificateAuthority
    Disallowed
    My
    Root
    TrustedPeople
    TrustedPublisher

  • Path — Specifies the path to a PFX file to export a self-signed certificate.

  • Password — Specifies the password for PFX file.

  • AllowSMIME — Enables Secure/Multipurpose Internet Mail Extensions for the certificate.

  • Exportable — Marks private key as exportable. Smart card providers usually do not allow
    exportable keys.

And several useful examples:

New-SelfsignedCertificateEx -Subject "CN=Test Code Signing" -EKU "Code Signing" -KeySpec "Signature" `-KeyUsage
 "DigitalSignature" -FriendlyName "Test code signing" -NotAfter [datetime]::now.AddYears(5)

Creates a self-signed certificate intended for code signing and which is valid for 5 years. Certificate is saved in the Personal store of the current user account.

New-SelfsignedCertificateEx -Subject "CN=www.domain.com" -EKU "Server Authentication", "Client authentication" `-KeyUsage
 "KeyEcipherment, DigitalSignature" -SAN "sub.domain.com","www.domain.com","192.168.1.1" `-AllowSMIME
 -Path C:\test\ssl.pfx -Password (ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force) -Exportable `-StoreLocation
 "LocalMachine"

Creates a self-signed SSL certificate with multiple subject names and saves it to a file. Additionally, the certificate is saved in the Personal store of the Local Machine store. Private key is marked as exportable, so you can export the certificate with a associated private key to a file at any time. The certificate includes SMIME capabilities.

New-SelfsignedCertificateEx -Subject "CN=www.domain.com" -EKU "Server Authentication", "Client authentication" `-KeyUsage
 "KeyEcipherment, DigitalSignature" -SAN "sub.domain.com","www.domain.com","192.168.1.1" `-StoreLocation
 "LocalMachine" -ProviderName "Microsoft Software Key Storae Provider" -AlgorithmName ecdh_256 `-KeyLength
 256 -SignatureAlgorithm sha256

Creates a self-signed SSL certificate with multiple subject names and saves it to a file. Additionally, the certificate is saved in the Personal store of the Local Machine store. Private key is marked as exportable, so you can export the certificate with a associated private key to a file at any time. Certificate uses Elliptic Curve Cryptography (ECC) key algorithm ECDH with 256-bit key. The certificate is signed by using SHA256 algorithm.

New-SelfsignedCertificateEx -Subject "CN=Test Root CA, OU=Sandbox" -IsCA $true -ProviderName `"Microsoft
 Software Key Storage Provider -Exportable

Creates self-signed root CA certificate.

Here is the code of the script. If you don’t want to read all this mess, scroll down and download ready file:

 

#####################################################################
# New-SelfSignedCertificateEx.ps1
# Version 1.6
#
# Creates self-signed certificate. This tool is a base replacement
# for deprecated makecert.exe
#
# Vadims Podans (c) 2013
# http://en-us.sysadmins.lv/
#####################################################################
#requires -Version 3.0

function New-SelfSignedCertificateEx {
[CmdletBinding(DefaultParameterSetName = '__store')]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Subject,
        [Parameter(Position = 1)]
        [datetime]$NotBefore = [DateTime]::Now.AddDays(-1),
        [Parameter(Position = 2)]
        [datetime]$NotAfter = $NotBefore.AddDays(365),
        [string]$SerialNumber,
        [Alias('CSP')]
        [string]$ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0",
        [string]$AlgorithmName = "RSA",
        [int]$KeyLength = 2048,
        [validateSet("Exchange","Signature")]
        [string]$KeySpec = "Exchange",
        [Alias('EKU')]
        [Security.Cryptography.Oid[]]$EnhancedKeyUsage,
        [Alias('KU')]
        [Security.Cryptography.X509Certificates.X509KeyUsageFlags]$KeyUsage,
        [Alias('SAN')]
        [String[]]$SubjectAlternativeName,
        [bool]$IsCA,
        [int]$PathLength = -1,
        [Security.Cryptography.X509Certificates.X509ExtensionCollection]$CustomExtension,
        [ValidateSet('MD5','SHA1','SHA256','SHA384','SHA512')]
        [string]$SignatureAlgorithm = "SHA1",
        [string]$FriendlyName,
        [Parameter(ParameterSetName = '__store')]
        [Security.Cryptography.X509Certificates.StoreLocation]$StoreLocation = "CurrentUser",
        [Parameter(Mandatory = $true, ParameterSetName = '__file')]
        [Alias('OutFile','OutPath','Out')]
        [IO.FileInfo]$Path,
        [Parameter(Mandatory = $true, ParameterSetName = '__file')]
        [Security.SecureString]$Password,
        [switch]$AllowSMIME,
        [switch]$Exportable
    )
    $ErrorActionPreference = "Stop"
    if ([Environment]::OSVersion.Version.Major -lt 6) {
        $NotSupported = New-Object NotSupportedException -ArgumentList "Windows XP and Windows Server 2003 are not supported!"
        throw $NotSupported
    }
    $ExtensionsToAdd = @()

#region constants
    # contexts
    New-Variable -Name UserContext -Value 0x1 -Option Constant
    New-Variable -Name MachineContext -Value 0x2 -Option Constant
    # encoding
    New-Variable -Name Base64Header -Value 0x0 -Option Constant
    New-Variable -Name Base64 -Value 0x1 -Option Constant
    New-Variable -Name Binary -Value 0x3 -Option Constant
    New-Variable -Name Base64RequestHeader -Value 0x4 -Option Constant
    # SANs
    New-Variable -Name OtherName -Value 0x1 -Option Constant
    New-Variable -Name RFC822Name -Value 0x2 -Option Constant
    New-Variable -Name DNSName -Value 0x3 -Option Constant
    New-Variable -Name DirectoryName -Value 0x5 -Option Constant
    New-Variable -Name URL -Value 0x7 -Option Constant
    New-Variable -Name IPAddress -Value 0x8 -Option Constant
    New-Variable -Name RegisteredID -Value 0x9 -Option Constant
    New-Variable -Name Guid -Value 0xa -Option Constant
    New-Variable -Name UPN -Value 0xb -Option Constant
    # installation options
    New-Variable -Name AllowNone -Value 0x0 -Option Constant
    New-Variable -Name AllowNoOutstandingRequest -Value 0x1 -Option Constant
    New-Variable -Name AllowUntrustedCertificate -Value 0x2 -Option Constant
    New-Variable -Name AllowUntrustedRoot -Value 0x4 -Option Constant
    # PFX export options
    New-Variable -Name PFXExportEEOnly -Value 0x0 -Option Constant
    New-Variable -Name PFXExportChainNoRoot -Value 0x1 -Option Constant
    New-Variable -Name PFXExportChainWithRoot -Value 0x2 -Option Constant
#endregion
    
#region Subject processing
    # http://msdn.microsoft.com/en-us/library/aa377051(VS.85).aspx
    $SubjectDN = New-Object -ComObject X509Enrollment.CX500DistinguishedName
    $SubjectDN.Encode($Subject, 0x0)
#endregion

#region Extensions

#region Enhanced Key Usages processing
    if ($EnhancedKeyUsage) {
        $OIDs = New-Object -ComObject X509Enrollment.CObjectIDs
        $EnhancedKeyUsage | %{
            $OID = New-Object -ComObject X509Enrollment.CObjectID
            $OID.InitializeFromValue($_.Value)
            # http://msdn.microsoft.com/en-us/library/aa376785(VS.85).aspx
            $OIDs.Add($OID)
        }
        # http://msdn.microsoft.com/en-us/library/aa378132(VS.85).aspx
        $EKU = New-Object -ComObject X509Enrollment.CX509ExtensionEnhancedKeyUsage
        $EKU.InitializeEncode($OIDs)
        $ExtensionsToAdd += "EKU"
    }
#endregion

#region Key Usages processing
    if ($KeyUsage -ne $null) {
        $KU = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage
        $KU.InitializeEncode([int]$KeyUsage)
        $KU.Critical = $true
        $ExtensionsToAdd += "KU"
    }
#endregion

#region Basic Constraints processing
    if ($PSBoundParameters.Keys.Contains("IsCA")) {
        # http://msdn.microsoft.com/en-us/library/aa378108(v=vs.85).aspx
        $BasicConstraints = New-Object -ComObject X509Enrollment.CX509ExtensionBasicConstraints
        if (!$IsCA) {$PathLength = -1}
        $BasicConstraints.InitializeEncode($IsCA,$PathLength)
        $BasicConstraints.Critical = $IsCA
        $ExtensionsToAdd += "BasicConstraints"
    }
#endregion

#region SAN processing
    if ($SubjectAlternativeName) {
        $SAN = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
        $Names = New-Object -ComObject X509Enrollment.CAlternativeNames
        foreach ($altname in $SubjectAlternativeName) {
            $Name = New-Object -ComObject X509Enrollment.CAlternativeName
            if ($altname.Contains("@")) {
                $Name.InitializeFromString($RFC822Name,$altname)
            } else {
                try {
                    $Bytes = [Net.IPAddress]::Parse($altname).GetAddressBytes()
                    $Name.InitializeFromRawData($IPAddress,$Base64,[Convert]::ToBase64String($Bytes))
                } catch {
                    try {
                        $Bytes = [Guid]::Parse($altname).ToByteArray()
                        $Name.InitializeFromRawData($Guid,$Base64,[Convert]::ToBase64String($Bytes))
                    } catch {
                        try {
                            $Bytes = ([Security.Cryptography.X509Certificates.X500DistinguishedName]$altname).RawData
                            $Name.InitializeFromRawData($DirectoryName,$Base64,[Convert]::ToBase64String($Bytes))
                        } catch {$Name.InitializeFromString($DNSName,$altname)}
                    }
                }
            }
            $Names.Add($Name)
        }
        $SAN.InitializeEncode($Names)
        $ExtensionsToAdd += "SAN"
    }
#endregion

#region Custom Extensions
    if ($CustomExtension) {
        $count = 0
        foreach ($ext in $CustomExtension) {
            # http://msdn.microsoft.com/en-us/library/aa378077(v=vs.85).aspx
            $Extension = New-Object -ComObject X509Enrollment.CX509Extension
            $EOID = New-Object -ComObject X509Enrollment.CObjectId
            $EOID.InitializeFromValue($ext.Oid.Value)
            $EValue = [Convert]::ToBase64String($ext.RawData)
            $Extension.Initialize($EOID,$Base64,$EValue)
            $Extension.Critical = $ext.Critical
            New-Variable -Name ("ext" + $count) -Value $Extension
            $ExtensionsToAdd += ("ext" + $count)
            $count++
        }
    }
#endregion

#endregion

#region Private Key
    # http://msdn.microsoft.com/en-us/library/aa378921(VS.85).aspx
    $PrivateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey
    $PrivateKey.ProviderName = $ProviderName
    $AlgID = New-Object -ComObject X509Enrollment.CObjectId
    $AlgID.InitializeFromValue(([Security.Cryptography.Oid]$AlgorithmName).Value)
    $PrivateKey.Algorithm = $AlgID
    # http://msdn.microsoft.com/en-us/library/aa379409(VS.85).aspx
    $PrivateKey.KeySpec = switch ($KeySpec) {"Exchange" {1}; "Signature" {2}}
    $PrivateKey.Length = $KeyLength
    # key will be stored in current user certificate store
    switch ($PSCmdlet.ParameterSetName) {
        '__store' {
            $PrivateKey.MachineContext = if ($StoreLocation -eq "LocalMachine") {$true} else {$false}
        }
        '__file' {
            $PrivateKey.MachineContext = $false
        }
    }
    $PrivateKey.ExportPolicy = if ($Exportable) {1} else {0}
    $PrivateKey.Create()
#endregion

    # http://msdn.microsoft.com/en-us/library/aa377124(VS.85).aspx
    $Cert = New-Object -ComObject X509Enrollment.CX509CertificateRequestCertificate
    if ($PrivateKey.MachineContext) {
        $Cert.InitializeFromPrivateKey($MachineContext,$PrivateKey,"")
    } else {
        $Cert.InitializeFromPrivateKey($UserContext,$PrivateKey,"")
    }
    $Cert.Subject = $SubjectDN
    $Cert.Issuer = $Cert.Subject
    $Cert.NotBefore = $NotBefore
    $Cert.NotAfter = $NotAfter
    foreach ($item in $ExtensionsToAdd) {$Cert.X509Extensions.Add((Get-Variable -Name $item -ValueOnly))}
    if (![string]::IsNullOrEmpty($SerialNumber)) {
        if ($SerialNumber -match "[^0-9a-fA-F]") {throw "Invalid serial number specified."}
        if ($SerialNumber.Length % 2) {$SerialNumber = "0" + $SerialNumber}
        $Bytes = $SerialNumber -split "(.{2})" | ?{$_} | %{[Convert]::ToByte($_,16)}
        $ByteString = [Convert]::ToBase64String($Bytes)
        $Cert.SerialNumber.InvokeSet($ByteString,1)
    }
    if ($AllowSMIME) {$Cert.SmimeCapabilities = $true}
    $SigOID = New-Object -ComObject X509Enrollment.CObjectId
    $SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
    $Cert.SignatureInformation.HashAlgorithm = $SigOID
    # completing certificate request template building
    $Cert.Encode()
    
    # interface: http://msdn.microsoft.com/en-us/library/aa377809(VS.85).aspx
    $Request = New-Object -ComObject X509Enrollment.CX509enrollment
    $Request.InitializeFromRequest($Cert)
    $Request.CertificateFriendlyName = $FriendlyName
    $endCert = $Request.CreateRequest($Base64)
    $Request.InstallResponse($AllowUntrustedCertificate,$endCert,$Base64,"")
    switch ($PSCmdlet.ParameterSetName) {
        '__file' {
            $PFXString = $Request.CreatePFX(
                [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)),
                $PFXExportEEOnly,
                $Base64
            )
            Set-Content -Path $Path -Value ([Convert]::FromBase64String($PFXString)) -Encoding Byte
        }
    }
}
content/scripts/New-SelfSignedCertificateEx.zip

Share this article:

Comments:

Woz

Hi Vadim, The script looks fantastic and perfectly timed for some work I'm doing where I need to create a self-signed certificate with more "detail" than I can achieve using MakeCert. I have Windows 7 with PowerShell 3 and .Net 4 (and also a Windows 8 PC). However, I'm not sure how to execute the script (I do have executionpolicy set to remotesigned). If I either run the script with no parameters, or follow it by an example nothing happens - the PowerShell prompt returns - with no errors. I'm sure this is just because I have too limited a knowledge of PowerShell. Could you advise how we actually run the script? Kind regards, Dave

Vadims Podans

I guess, you incorrectly calling the command. In the PowerShell console, you need to do the following: . .\New-SelfSignedCertificateEx.ps1 note the first dot. It is dot-source operator in PowerShell which attaches the function in the current PowerShell session. Taht is, you need to type dot, space and the path to a PS1 file. And then you can run the function with parameters.

Tony Mulvihill

Quite interesting however an item I'm looking for is the ability to create a SAN certificate signed off a specified root CA cert. MakeCert does it but unfortunately lacks the ability to add the SAN attribute. Can you advise? I'm not a developer so lets not get too technical ;-)

Vadims Podans

If you want to sign certificate by a CA, then you should generate certificate request and submit it to a CA server. I guess, you want to get random certificate and self-signed certificate? No, I don't provide such functionality and it falls to another story (which is not common nowadays).

YURI

Great work! just a remark in my PowerShell 4.0 -NotAfter [datetime]::now.AddYears(5) does work only that way ([datetime]::now.AddYears(5)) in parenthesis.

Vadims Podans

Yes, it is a typo in the example. Thanks for clarification.

JayS

Hi there, First: Thanks for this great script. My question: how is this script licensed? Is it possible to use this script in a powershell module which should be published on codeplex for everyone. I will not use this code in any commercial manner. Regards JayS

Vadims Podans

The script is licensed under MS-PL license. You can use the script as is and modify as per your needs. However, you will have to maintain a copyright note.

Abe

Hello Vadims,

Thank you for creating this great script! I ran into the following error when trying to generate a self-signed script:

Method invocation failed because [System.Collections.Generic.Dictionary`2+KeyCollection[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] doesn't contain a method named 'Contains'.

At C:\Users\test\Desktop\New-SelfSignedCertificateEx.ps1:267 char:38

I was able to fix this error by enclosing $PSBoundParameters within double-quotation marks on line 267:

#region Basic Constraints processing
    if ("$PSBoundParameters".Keys.Contains("IsCA")) {

Then I encountered the following error:

You cannot call a method on a null-valued expression.
At C:\Users\test\Desktop\New-SelfSignedCertificateEx.ps1:267 char:40

I ended up commenting out the entire region for Basic Constrains Processing from line 266 to 276. This allowed me to run your script and generate a self-signed certificate. I just wanted to let you know the error I encountered. Again, thank you for creating this script!

 

Abe

Hello Vadims,

Thank you for creating this great script! I ran into the following error when trying to generate a self-signed script:

Method invocation failed because [System.Collections.Generic.Dictionary`2+KeyCollection[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] doesn't contain a method named 'Contains'.

At C:\Users\test\Desktop\New-SelfSignedCertificateEx.ps1:267 char:38

I was able to fix this error by enclosing $PSBoundParameters within double-quotation marks on line 267:

#region Basic Constraints processing
    if ("$PSBoundParameters".Keys.Contains("IsCA")) {

Then I encountered the following error:

You cannot call a method on a null-valued expression.
At C:\Users\test\Desktop\New-SelfSignedCertificateEx.ps1:267 char:40

I ended up commenting out the entire region for Basic Constrains Processing from line 266 to 276. This allowed me to run your script and generate a self-signed certificate. I just wanted to let you know the error I encountered. Again, thank you for creating this script!

 

Zoltan Erszenyi

The script runs without errors and no output on the console. However I cannot find the certificate. Looked at both user and computer stores.

Where is the cert supposed to be placed?

Thank you.

Vadims Podāns

> Where is the cert supposed to be placed?

it should be installed in either, CurrentUser\My or LocalMachine\My store. What parameters did you use?

Tau Wan

Hi, 

I tried to run this script from the powershell with administrator rights but it runs without errors and no output on the console. I also cannot find the certificate in CurrentUser and LocalMachine store.

.\New-SelfsignedCertificateEx.ps1 -Subject "CN=portal-dev-app.corp.com" -EKU "Server Authentication", "Client authentication" -KeyUsage "KeyEcipherment, DigitalSignature" -Path "C:\Shared\ssl.pfx" -Password (ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force) -Exportable -StoreLocation "LocalMachine" -NotAfter [datetime]::now.AddYears(5)

Please advise.

Thanks

Vadims Podāns

You didn't import the function to the PowerShell console. You need to dot-source the script and then run the New-SelfSignedCertificateEx function.

Khaleel Hmoz

Can you help me please in this question ? :

Why in New-SelfSignedCertificateEx there is no parameter "Signer" which can create a leaf certificate under existed CA ?  allthough "Signer" parameter is existed in New-SelfSignedCertificate (which is built-in Windows 10 )

Vadims Podāns

> Why in New-SelfSignedCertificateEx there is no parameter "Signer" which can create a leaf certificate under existed CA ?

because such certificate is no longer self-signer. For existing CAs you have to generate certificate request and use CA tools to sign the request.

Artem

Hi. I get the error when try to pass -Path param

"New-SelfSignedCertificateEx : Parameter set cannot be resolved using the specified named parameters.
At C:\CreateSslCert.ps1:52 char:11
+   $cert = New-SelfSignedCertificateEx -Subject "CN=localhost" -StoreL .."

$cert = New-SelfSignedCertificateEx -Subject "CN=localhost" -StoreLocation "LocalMachine" -SubjectAlternativeName $hosts -FriendlyName $name -NotAfter $((Get-Date).AddYears(20)) -Exportable -IsCA $true -Path "$HOME\AppData\Local\cert.pfx"  -Password (ConvertTo-SecureString "123" -AsPlainText -Force) -Exportable


The reaseon is in -Path for sure. But why?

Vadims Podāns

Well, the issue is that "-Path" and "-StoreLocation" parameters are mutually exclusive and cannot be used together.

Kevin Obee

> Why in New-SelfSignedCertificateEx there is no parameter "Signer" which can create a leaf certificate under existed CA ?

because such certificate is no longer self-signer. For existing CAs you have to generate certificate request and use CA tools to sign the request.

@Vadims do you have examples for how to use the CA certificate to sign client certificates that can be used to bind HTTPS to a website just using PowerShell?

 

Vadims Podāns

> @Vadims do you have examples for how to use the CA certificate to sign client certificates that can be used to bind HTTPS to a website just using PowerShell?

this functionality exists in standard New-SelfSignedCertificate cmdlet with -Signer parameter that accepts signer certificate with private key.

Bob

>this functionality exists in standard New-SelfSignedCertificate cmdlet with -Signer parameter that accepts signer certificate with private key.

The "-Signer" and many other params aren't available with New-SelfSignedCeriticate in Windows 8.1, even if you install WMF 5.1.  Actually I ended up on this page, I think , by a comment you made elsewhere stating exactly this fact, which is why I was trying to use your script.

I successfully installed a self-signed key (your first examlpe) and used it to sign a DLL for VirtualBox (which requires injected DLLs to have a signature), but it's failing with error VERR_CR_X509_CPV_NO_TRUSTED_PATHS.  I'm thinking the "No trusted paths" error means that it wants a separate CA certificate, even though I imported that signing key into the "trusted root certicate authority."  But I don't think I can use powershell to achieve this, as stated.

Vadims Podāns

> I imported that signing key into the "trusted root certicate authority."

I can think that public part of certificate must be imported into Local Machine store, not current user store.

Ian Peter Murphy

Hi Vadim,

I've just been trying to use your script on a win11 machine. After getting stuck I tried your examples which you posted avode and they do not work either.

For example, if I execute New-SelfsignedCertificateEx -Subject "CN=Test Code Signing" -EKU "Code Signing"  -FriendlyName "Test code signing" -NotAfter (Get-Date).addyears(10)  -notbefore (get-date)

I get an error

% : CertEnroll::CObjectId::InitializeFromValue: El parámetro no es correcto. 0x80070057 (WIN32: 87
ERROR_INVALID_PARAMETER)
En C:\temp\New-SelfSignedCertificateEx.ps1: 99 Carácter: 29
+         $EnhancedKeyUsage | %{
+                             ~~
    + CategoryInfo          : OperationStopped: (:) [ForEach-Object], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ForEachObjectCommand

Most of your examples seem to provoke errores.

I'll keep on digging but I'm getting errors with many of the params.

 


Post your comment:

Please, solve this little equation and enter result below. Captcha