New-SelfSignedCertificate on Win2012 r2 has less parameters - powershell

I'm trying to create a self signed certificate with specific encryption parameter values.
On a Win Server 2012 r2 standard running PowerShell 5.0, when I attempt to use
New-SelfSignedCertificate
I receive an error:
New-SelfSignedCertificate : A parameter cannot be found that matches parameter name 'Subject'.
when I attempt to use the -Subject parameter, which in addition to other parameters allowed on my laptop, does not appear in the intellisense.
However on my laptop (Win 10 and PowerShell 5.0) I'm allowed to use these parameters, and I create a self-signed certificate by using the following code
#create a Certificate
# OID for document encryption
$Oid = New-Object System.Security.Cryptography.Oid "1.3.6.1.4.1.311.80.1"
$oidCollection = New-Object System.Security.Cryptography.OidCollection
$oidCollection.Add($oid) > $Null
# Create enhanced key usage extension that allows document encryption
$Ext = New-Object System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension $oidCollection, $true
$myCert = New-SelfSignedCertificate -Subject 'CN=myservernameasubject' -CertStoreLocation "Cert:\LocalMachine\My" -KeySpec KeyExchange -KeyUsage KeyEncipherment, DataEncipherment -Extension $Ext

Use -DnsName instead without the CN=.
From the PowerShell help:
-DnsName <String>
Specifies one or more DNS names to put into the Subject Alternative Name extension of the certificate when a certificate to be
copied is not specified via the CloneCert parameter. The first DNS
name is also saved as Subject Name and Issuer Name.
The -KeySpec and other related options are, unfortunately, not supported by New-SelfSignedCertificate in Windows Server 2012 R2 and Windows 8.1. Otherwise, you're looking at one of three options to generate the desired certificate; Adapt the COM object based code in the answer to How to create a self-signed certificate using C#? to use in PowerShell, use an external executable like makecert.exe, or generate the certificate/key pair elsewhere and then import it to the certificate store on the other machine.
Update: After further research, it looks like adapting COM based code in PowerShell is a good option. I found a blog entry by Vishal Agarwal, Generating a certificate (self-signed) using powershell and CertEnroll interfaces, that gives the following PowerShell code:
$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=TestServer", 0)
$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = get-date
$cert.NotAfter = $cert.NotBefore.AddDays(90)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")

The following worked just fine for the self-signed option...
New-SelfSignedCertificate -DnsName "*.costoso100.com" -CertStoreLocation "cert:\LocalMachine\My"
I was able to export and setup LDAPS in about 15 minutes.

Related

Bypass Internet Explorer certificate warning

My Question is pretty straight forward.
Can I somehow bypass this warning in PowerShell?
Right now I'm loading the website with the InternetExplorer.Application ComObject, but I could switch to Invoke-Webrequest etc. if that's needed
EDIT: Additional information
This is just for a function I wrote to open ILO of our HP Servers via PowerShell. that's the function:
function Open-ILO {
param(
[Parameter(
Position = 0,
Mandatory = $true
)]
[string]$computer,
[switch]$show
)
$hash = #{
"Server1" = "http://10.0.0.49/"
"Server2" = "http://10.0.0.50/"
"Server3" = "http://10.0.0.56/"
}
$Wert = $hash.get_item($computer)
if (!$show.IsPresent)
{
$ie = new-object -com InternetExplorer.Application
$ie.Visible = $true
$ie.Navigate($Wert)
}
else { Write-Host $Wert }
}
The issue here isn't PowerShell it's Internet Explorer.
The ILO comes with a self-signed certificate which IE does not trust and so shows you the error. Self-signed certificates are not trusted as they are self-generated and require no verification from a certificate authority.
You can either generate a new cert for the ILO from an internal certificate authority to replace the self signed cert. If you are using Active Directory you will have a CA.
Or you can install the self-signed certificate so that IE trusts it.
Depending on your workplace security policy there might be security concerns with the second option, as your computer will trust content that is signed with that certificate. Most businesses will be ok with this but some with high security might not.

How to create the code signing certificate through the New-SelfSignedCertificate cmdlet

PowerShell 4.0
makecert tool has the -eku option for describing the enhanced key usage object identifiers (OIDs) into the certificate. It allows to make the certificates for code signing and for other purposes. But it is not a cmdlet.
New PowerShell versions have the New-SelfSignedCertificate cmdlet for local testing of the scripts. But it creates the certificate that can't be used for code signing:
New-SelfSignedCertificate -DnsName www.SomeSite.com -CertStoreLocation Cert:\CurrentUser\My
I don't see an option which is similar of -eku.
How can I set the destination of my new Self-Signed Certificate (created through New-SelfSignedCertificate cmdlet) for possibility of its use for code signing? Or is it possible to do the same via other cmdlet?
The version of New-SelfSignedCertificate on PS 4 is rather basic.
However Powershell v5 has the parameters that you would require to create specific keys.
Specifically a Keyusage parameter that takes
-- CertSign
-- CRLSign
-- DataEncipherment
-- DecipherOnly
-- DigitalSiganture
-- EncipherOnly
-- KeyAgreement
-- KeyEncipherment
-- None (default)
-- NonRepudiation
and a KeyUsageProperty taking
-- All
-- Decrypt
-- KeyAgreement
-- None (default)
-- Sign
Are you specifically tied to v4? If you can upgrade to v5 you should be able to achieve what you need.
Reviving this question as I was also looking for an answer to set Enhanced Key Usage (EKU) field for code signing using PowerShell New-SelfSignedCertificate command.
It can be done using the -TextExtension parameter to set EKU value. As an example, the following PowerShell (tested on PowerShell 5.1) script allows to create a 3-years self signed code signing certificate with extended key usage (and export it from the current user's certificates store to pfx file format):
# Enhanced Key Usage
$EKU = "2.5.29.37"
$EKU_CODE_SIGNING = "1.3.6.1.5.5.7.3.3"
$certificate = New-SelfSignedCertificate -Subject "CN=Testing Code Signing,E=info#mycompany.com,O=My Company" `
-FriendlyName "My Code Signing Certificate" `
-NotAfter (Get-Date).AddYears(3) `
-CertStoreLocation Cert:\CurrentUser\My `
-TextExtension #("$EKU={text}$EKU_CODE_SIGNING")
$password = ConvertTo-SecureString -String "mypassword" -Force -AsPlainText
Export-PfxCertificate -Cert "Cert:\CurrentUser\My\$($certificate.Thumbprint)" -FilePath "codesigning.pfx" -Password $password
Note: As a shortcut, the -Type CodeSigningCert parameter can be specified with the New-SelfSignedCertificate command instead of explicitly adding the EKU_CODE_SIGNING string to the -TextExtension parameter.
You can use PS' cert provider to access different cert stores (user vs machine), but that won't help with your OID problem. I suggest you look at .NET support for X509 certs. Google ".net x509 certificate" and you'll find the X509Certificate class on MSDN. From there read the class documentation and any overview documentation to see if creation of OIDs is supported. If .NET doesn't support it then you'd have to use P/Invoke to invoke native Windows CNG (cryptography next generation) APIs

Connection to mainframe and Unix to get certificate information

I have a program that works good to get certificate information, but only for Windows boxes. I need it to work for UNIX and mainframe. I added the cert to the Windows trusted root cert auth and have the root cert there as well. I did not generate my own cert here as I didn't think it was needed.
It blows up on the last line where it does an auth, with the error
The remote certificate is invalid according to the validation procedure.
Any ideas what to check for?
$certpath = "C:\Certdir\Certificates\xxx.cer"
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromCertFile($certPath)
[System.Security.Authentication.SslProtocols]$protocol = "TLS"
$certcol = New-Object System.Security.Cryptography.X509Certificates.X509CertificateCollection
$certcol.Add($cert)
$socket = New-Object Net.Sockets.TcpClient($computerName, $port)
$stream = $socket.GetStream()
$sslStream = New-Object System.Net.Security.SslStream $stream,$false
$sslStream.AuthenticateAsClient($computerName,$certcol,$protocol,$false)

Powershell Script to Install Certificate Into Active Directory Store

I'm trying to write a powershell script to install a certificate into the active directory certificate store,
Here are the steps to do this manually, any help would be greatly appreciated.
On a Windows 2008R2 domain controller,
Click Start -> Run
type MMC
click ok
Click File -> Add/Remove Snap-In
Select "Certificates" -> Add
Select "Service Account"
Click Next
Select "Local Computer"
Click Next
Select "Active Directory Domain Services"
Click Finish
Click Ok
I want the script to install the certificate into :
NTDS\Personal
I would post an image but I don't have enough "reputation" apparently, so I can only provide text instructions.
So basically what I've tried is, I've used this powershell function below to import a certificate into the Local Machine -> Personal Store, which is where most certificates go, and the code works.
But I need to install the certificate into the "NTDS\Personal" store on a domain controller, but the $certRootStore only accepts localmachine or CurrentUser, so I'm stuck : /
function Import-PfxCertificate
{
param
(
[String]$certPath,
[String]$certRootStore = "localmachine",
[String]$certStore = "My",
$pfxPass = $null
)
$pfx = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
if ($pfxPass -eq $null)
{
$pfxPass = read-host "Password" -assecurestring
}
$pfx.import($certPath,$pfxPass,"Exportable,PersistKeySet")
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certStore,$certRootStore)
$store.open("MaxAllowed")
$store.add($pfx)
$store.close()
}
Import-PfxCertificate -certPath "d:\Certificate.pfx"
Regards Alex
Using a combination of what you already had above and the registry keys for the two certificate stores this works.
The only other thing is that I don't know how NTDS determines which certificate to use when there are multiple in the certificate store.
function Import-NTDSCertificate {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$PFXFile,
[Parameter(Mandatory)]
[string]$PFXPassword,
#Remove certificate from LocalMachine\Personal certificate store
[switch]$Cleanup
)
begin{
Write-Verbose -Message "Importing PFX file."
$PFXObject = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2
$PFXObject.Import($PFXFile,$PFXPassword,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$thumbprint = $PFXObject.Thumbprint
}
process{
Write-Verbose -Message "Importing certificate into LocalMachine\Personal"
$certificateStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store('My','LocalMachine')
$certificateStore.Open('MaxAllowed')
$certificateStore.Add($PFXObject)
$certificateStore.Close()
Write-Verbose -Message "Copying certificate from LocalMachine\Personal to NTDS\Personal"
$copyParameters = #{
'Path' = "HKLM:\Software\Microsoft\SystemCertificates\MY\Certificates\$thumbprint"
'Destination' = "HKLM:\SOFTWARE\Microsoft\Cryptography\Services\NTDS\SystemCertificates\My\Certificates\$thumbprint"
'Recurse' = $true
}
Copy-Item #copyParameters
}
end{
if ($Cleanup){
Write-Verbose -Message "Removing certificate from LocalMachine\Personal"
$removalParameters = #{
'Path' = "HKLM:\SOFTWARE\Microsoft\SystemCertificates\MY\Certificates\$thumbprint"
'Recurse' = $true
}
Remove-Item #removalParameters
}
}
}
Alright, first the bad news. The only managed certificate stores are LocalMachine and CurrentUser, as we have all seen in powershell.
Now, the not so bad news. We know that the 'physical' location store (physical is MS' word, not mine) exists in the registry on the ADDS server, HKLM\Software\Microsoft\Cryptography\Services\NTDS\SystemCertificates. This was dually verified by both
Using procmon while importing a certificate into the store using the mmc snap-in
Scavenging msdn for this nugget
The link in #2 shows that all physical stores for services are stored in the path mentioned above, substituting NTDS for . The real service name, not the display name.
However,
Because of the bad news. Trying to map it in powershell with that reg key as the root and -PSProvider Certificate will prove disappointing, it was the first thing I tried.
What one can try, is using the X509Store constructor that takes an IntPtr to a SystemStore, as described here. Yes, that invovles some unmanaged code, and mixing the two is something I do rarely, but this and googling for HCERTSTORE C# should get you there.
Even though this post is years old, it is still helpful and turns up in searches, so to address the question of "I don't know how NTDS determines which certificate to use when there are multiple in the certificate store", the answer is that you will get unreliable results when there are two or more valid certificates installed that meet the requested criteria so it is recommended to remove the old/unneeded certificate(s) and just leave the newest/best one for the server auth.

Using PowerShell to Create Self-Signed Certificate

I'm using code similar to that found here to create a self-signed certificate for use in IIS:
http://blogs.technet.com/b/vishalagarwal/archive/2009/08/22/generating-a-certificate-self-signed-using-powershell-and-certenroll-interfaces.aspx
Works fine except I want to give it a friendly name to make locating it easier when I want to assign the certificate to a dynamically created site.
Anyone know how to change the above to set the friendly name (I've tried what seemed obvious to no avail).
Got a better way to create a cert via PowerShell that does not prompt the user for information?
Followup on the script I am using - based on the url above but turned into a cmdlet:
function Add-SelfSignedCertificate
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)]
[Alias('cn')]
[string]$CommonName
)
$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$CommonName", 0)
$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 1024
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = get-date
$cert.NotAfter = $cert.NotBefore.AddDays(90)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
}
It might not help for your specific use, but there is a new Powershell CmdLet installed in Windows 8.1 and Server 2012 that is pretty quick and easy to use:
New-SelfSignedCertificate [-CertStoreLocation <String> ] [-CloneCert <Certificate> ] [-DnsName <String> ] [-Confirm] [-WhatIf] [ <CommonParameters>]
More details can be found here: https://learn.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps
In my usage, the friendly name of the cert has always been set as the first DnsName specified in the CmdLet.
Example that places the certificate in your Local Computer's Personal store:
New-SelfSignedCertificate -CertStoreLocation cert:\LocalMachine\My -DnsName www.example.com
Note: Powershell has to be started with admin rights for this to work.
You can set the CertificateFriendlyName directly in you code, you just need to know where to do it:
$enrollment.InitializeFromRequest($cert)
$enrollment.CertificateFriendlyName = 'whatever'
$certdata = $enrollment.CreateRequest(0)
$key has a FriendlyName but I don't see that showing up anywhere so I don't think it helps you.
Scott Hanselman wrote up a nice blog post on how to create a self-signed cert using the SDK tool makecert.exe. That tool looks to be a good bit easer to use than the code in the post you reference. With makecert.exe you can use the -n option to specify a subject name. I've used that subject name to refer to the certificate in other tools like signtool.exe. Although, I've found that subject names don't have to be unique so I tend to use the Thumbprint value which appears to be unique. Signtool will also accept a thumbprint (via the /sha1 parameter) to identify the cert.