I am using the New-SelfSignedCertificate cmdlet to create self-signed certificate as indicated by Microsoft documentation of that cmdlet:
Cert:\LocalMachine\My>New-SelfSignedCertificate -Type Custom -Subject "CN=Patti Fuller,OU=UserAccounts,DC=corp,DC=contoso,DC=com" -TextExtension #("2.5.29.37={text}1.3.6.1.5.5.7.3.2","2.5.29.17={text}upn=pattifuller#contoso.com") -KeyUsage DigitalSignature -KeyAlgorithm RSA -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My"
But there is no output created in “Cert:\LocalMachine\My” location?
Am I doing anything wrong?
Related
I ran the following Azure command in PowerShell to fetch the keyvault certificate:
Get-AzureKeyVaultCertificate -VaultName "ssl-keyvault-appservice" -Name "PI"
I got the output
Since I'm new to PowerShell, I'm not sure how to retrieve the thumbprint alone. I searched for Azure PowerShell command for thumbprint alone, but I can't find anything.
Is there any way in PowerShell to get only the thumbprint property alone?
You could run the following -
(Get-AzureKeyVaultCertificate -VaultName "ssl-keyvault-appservice" -Name "PI").Thumbprint
OR
Get-AzureKeyVaultCertificate -VaultName "ssl-keyvault-appservice" -Name "PI" | Select -property Thumbprint
I need to automate creating a keyvault and adding two certificates to the vault. I have one self-signed without a password and one wildcard cert signed from a valid authority.
When I try and import them the signed cert gets added fine but the self-signed returns an error...
Import-AzureKeyVaultCertificate : Pending Certificate not found: cluster-app-primary
At script.ps1:18 char:1
Import-AzureKeyVaultCertificate -VaultName $name -Name 'cluster-app...
+ CategoryInfo : CloseError: (:) [Import-AzureKeyVaultCertificate], KeyVaultErrorException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.KeyVault.ImportAzureKeyVaultCertificate
The powershell code is as follows:
Import-AzureKeyVaultCertificate -VaultName $name -Name 'cluster-app-primary' -FilePath "..\..\Certificates\cluster-app-primary.pfx"
Now the exact same command with the other certificate works fine (with a password though).
Also note that if I try and import the self-signed certificate through the Azure portal it works fine.
Does anyone know what this error means and is there anything I can do to import this thru powershell?
Thanks.
I think this issue related to your self-signed cert, the command works fine on my side. Try to create a pfx certificate with a password like below, becasue when you import the certificate in the portal, it also asks for a password.
$certroopath = "C:\Users\Administrator\Desktop"
$certname = "mycert1"
$certpassword = "P#ssw0rd1234"
$cert = New-SelfSignedCertificate -DnsName "$certname" -CertStoreLocation cert:\CurrentUser\My
$pwd = ConvertTo-SecureString -String $certpassword -Force -AsPlainText
$certwithThumb = "cert:\CurrentUser\my\"+$cert.Thumbprint
$filepath = "$certroopath\$certname.pfx"
Export-PfxCertificate -cert $certwithThumb -FilePath $filepath -Password $pwd
Then import it to azure keyvault, it works fine.
$mypwd = ConvertTo-SecureString -String "P#ssw0rd1234" -Force -AsPlainText
Import-AzKeyVaultCertificate -VaultName joykeyvault -Name testc1 -FilePath C:\Users\Administrator\Desktop\mycert1.pfx -Password $mypwd
UPDATE
I could not get this to work so what I did was use the CertificateString parameter instead. I just took the string of the exact same certificate and it worked fine and imported it.
Import-AzKeyVaultCertificate -VaultName $name -Name $certName -CertificateString "MII..."
With the following command I am able to generate self-signed certificate at PowerShell prompt:
$mycert = New-SelfSignedCertificate -DnsName "myhost.westeurope.cloudapp.azure.com" -CertStoreLocation "cert:\LocalMachine\My"
Then I can export it to a PFX file:
$mypwd = ConvertTo-SecureString -String "1234" -Force –AsPlainText
Export-PfxCertificate -FilePath .\mycert.pfx -Password $mypwd -Cert $mycert
Finally, I can import the certificate into Azure Keyvault:
$kvcert = Import-AzKeyVaultCertificate -VaultName mykeyvault -Name mycert -FilePath .\mycert.pfx -Password $mypwd
The above commands work well for me and I can call Import-AzKeyVaultCertificate repeatedly without any errors. Which is important for me, because I want to call the command from an Azure pipeline as a build for pull requests in our team.
My question is -
I don't want to commit the PFX file into our Git repo.
Instead I want to inline the base64 content of it in a PowerShell script, just to have 1 less file in the repo and not having to figure out URL and SAS token for the pipeline.
I am able to base64 format the PFX file content with the follwoing commands at the PowerShell:
$Bytes = [System.IO.File]::ReadAllBytes("c:\tmp\mycert.pfx");
$Base64 = [System.Convert]::ToBase64String($Bytes);
And now I could copy-paste it into my PowerShell script with $Base64 = "D3AB.....ICB9A==";
But how to pass it to the Import-AzKeyVaultCertificate command in my script?
Is there some trick like echo $Base64 | Import-AzKeyVaultCertificate -FilePath - like in Linux for STDIN?
I'm trying to automate the process of generating a certificate signing request and then importing the response from the CA on a Windows Server 2012 R2 server to use as a cert for a SSL binding in IIS. I'm able to generate the CSR which I then provide to the security team which then provides me with a response to then import but am having troubles getting it to import.
This server is in a workgroup. Thought I'd mention that so no AD enrollment policy.
Here's my process:
Generate a CSR with certreq.exe on the server in question. An INF file is generated that looks something like this:
[Version]
Signature = "$Windows NT$"
[NewRequest]
Subject = "C=US,S=California,L=City,O=Company,OU=IT,CN=hostname"
Exportable = TRUE
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xa0
MachineKeySet = True
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
Silent = True
SMIME = False
RequestType = PKCS10
This INF file then gets turned into the CSR .req file by doing this:
certreq.exe -new "C:\inffile.inf" "C:\certreq.req"
The REQ file gets sent to the security team and they give me back a .CER file, which, when imported manually, actually adds three certificates from Digicert. The certificate I expect and what looks to be some intermediate CAs.
Here's what that looks like when imported via the MMC Certificates snapin.
If I import the certificate via the MMC like this it doesn't show up in the IIS manager under Server Certificates so I looked a little deeper. I tried to complete the certificate signing request via the the IIS manager like this and the cert shows up and I'm happy.
However, I can't use the GUI since I'm using a script.
I confirm that the request is in Certificate Enrollment Requests with the private key.
I confirm that the public key of the CSR and the p7b I got back provided are the same.
certutil -dump issuedcert.cer
certutil -dump certreq.req
PROBLEM: I exported the CSR from Certificate Enrollment Requests and looked at the public key. It was NOT the same as the one in issuedcert.cer. It looks like this is the problem but why?
I then try to use certreq.exe to accept the response and it doesn't work.
certreq.exe -accept -machine "C:\issuedcert.cer"
Almost done, but no. I continually receive this error message:
This error indicates that certreq was unable to find related request object in the Certificate Enrollment Requests node in the certificate store.
In addition, I would suggest to check whether the public key in the certificate request match the one in the issued certificate. You can use certutil -dump file.req command to dump request file (there will be public key) and cerutil -dump cert.cer to dump issued certificate and compare public keys. Do the same for each object in the Certificate Enrollment Requests node in the certificate store (focused on Local Machine context) to find request object with matching public key.
here is the function i've used in the past:
function AddCertificate(
[string] $MachineName,
[string] $CertString, #String to search for in the Certificate Store to get the correct Thumbprint
[string] $SiteName, #Sitename to bind the certificate to.
[string] $certname, #File name of the certificate
[string] $certPass, #Password for the certificate
[string] $certPath) #path on the machine where this script runs that contains the certificate path needs to not have a Trailing \
{
$Protocol = "https"
$destinationFolder = "c$\temp\pfx-files"
$servers = $MachineName
$session = New-PsSession –ComputerName $servers
$servers | foreach-Object{if(!(Test-Path -path ("\\$_\"+$destinationFolder))) {New-Item ("\\$_\"+$destinationFolder) -Type Directory}}
$servers | foreach-Object{copy-item -force -Path c:\temp\pfx-files\*.* -Destination ("\\$_\"+$destinationFolder)}
$certPath ="c:\temp\pfx-files" +"\"+$certname
Invoke-command -Session $session -ScriptBlock {param($certPass,$certPath) certutil -p $certPass -importpfx ($certPath )}
$servers | foreach-object {Remove-Item -Path (("\\$_\"+$destinationFolder) +"\*.pfx")}
Invoke-Command -session $session {Import-Module WebAdministration}
$isBound = Invoke-Command -session $session {Get-WebBinding }
if (!(Select-String -Pattern "https" -InputObject $isbound -quiet))
{
Invoke-command -Session $session -ScriptBlock {param([string] $S, [string] $Protocol)( New-WebBinding -Name $S -Protocol $Protocol -Port 443 -IPAddress "*" -SslFlags 0)} -ArgumentList $SiteName, $Protocol
Invoke-Command -session $session -ScriptBlock { param([string]$Certstring) $CertShop=Get-ChildItem -Path Cert:\LocalMachine\My | where-Object {$_.subject -like $CertString } | Select-Object -ExpandProperty Thumbprint}
Invoke-Command -Session $session -ScriptBlock {get-item -Path "cert:\localmachine\my\$certShop" | new-item -path IIS:\SslBindings\0.0.0.0!443}
}
Exit-PSSession
}
Adam, try to rename your .cer to .p7b and try certreq -accept file.p7b.
Certreq seems look for the file extension to determine the file type. It supports p7b file for -accept according to the MS docs.
The problem might be that DigiCert Root CA is not trusted in your windows 2012 system. Try to import it manually into the Trusted Root Authorities in LocalMachine store.
Then I would check if there is still a request in Certificate Enrollment Requests in LocalMachine store using MMC.
If there is then it should work fine to just import the given certificate to LocalMachine/My store (in MMC the name is Personal)
If there is not a request there then import certificate in LocalMachine/My store. Then run certutil -store my in cmd. It will go through all certificates in LocalMachine/My, display information about them and try to do encryption test. I assume that all encryption tests will fail. The important thing is to get index of your certificate (certificates begin with index 0). Find the number of the certificate and then use command
certutil -repairstore -csp "Microsoft RSA SChannel Cryptographic Provider" {index of the certificate}
This will try to repair the connection between certificate and private key. When you run certutil -store my again you should see encryption test passed.
How do I create a self-signed certificate for code signing using tools from the Windows SDK?
Updated Answer
If you are using the following Windows versions or later: Windows Server 2012, Windows Server 2012 R2, or Windows 8.1 then MakeCert is now deprecated, and Microsoft recommends using the PowerShell Cmdlet New-SelfSignedCertificate.
If you're using an older version such as Windows 7, you'll need to stick with MakeCert or another solution. Some people suggest the Public Key Infrastructure Powershell (PSPKI) Module.
Original Answer
While you can create a self-signed code-signing certificate (SPC - Software Publisher Certificate) in one go, I prefer to do the following:
Creating a self-signed certificate authority (CA)
makecert -r -pe -n "CN=My CA" -ss CA -sr CurrentUser ^
-a sha256 -cy authority -sky signature -sv MyCA.pvk MyCA.cer
(^ = allow batch command-line to wrap line)
This creates a self-signed (-r) certificate, with an exportable private key (-pe). It's named "My CA", and should be put in the CA store for the current user. We're using the SHA-256 algorithm. The key is meant for signing (-sky).
The private key should be stored in the MyCA.pvk file, and the certificate in the MyCA.cer file.
Importing the CA certificate
Because there's no point in having a CA certificate if you don't trust it, you'll need to import it into the Windows certificate store. You can use the Certificates MMC snapin, but from the command line:
certutil -user -addstore Root MyCA.cer
Creating a code-signing certificate (SPC)
makecert -pe -n "CN=My SPC" -a sha256 -cy end ^
-sky signature ^
-ic MyCA.cer -iv MyCA.pvk ^
-sv MySPC.pvk MySPC.cer
It is pretty much the same as above, but we're providing an issuer key and certificate (the -ic and -iv switches).
We'll also want to convert the certificate and key into a PFX file:
pvk2pfx -pvk MySPC.pvk -spc MySPC.cer -pfx MySPC.pfx
If you are using a password please use the below
pvk2pfx -pvk MySPC.pvk -spc MySPC.cer -pfx MySPC.pfx -po fess
If you want to protect the PFX file, add the -po switch, otherwise PVK2PFX creates a PFX file with no passphrase.
Using the certificate for signing code
signtool sign /v /f MySPC.pfx ^
/t http://timestamp.url MyExecutable.exe
(See why timestamps may matter)
If you import the PFX file into the certificate store (you can use PVKIMPRT or the MMC snapin), you can sign code as follows:
signtool sign /v /n "Me" /s SPC ^
/t http://timestamp.url MyExecutable.exe
Some possible timestamp URLs for signtool /t are:
http://timestamp.verisign.com/scripts/timstamp.dll
http://timestamp.globalsign.com/scripts/timstamp.dll
http://timestamp.comodoca.com/authenticode
http://timestamp.digicert.com
Full Microsoft documentation
signtool
makecert
pvk2pfx
Downloads
For those who are not .NET developers, you will need a copy of the Windows SDK and .NET framework. A current link is available here: [SDK & .NET][5] (which installs makecert in `C:\Program Files\Microsoft SDKs\Windows\v7.1`). Your mileage may vary.
MakeCert is available from the Visual Studio Command Prompt. Visual Studio 2015 does have it, and it can be launched from the Start Menu in Windows 7 under "Developer Command Prompt for VS 2015" or "VS2015 x64 Native Tools Command Prompt" (probably all of them in the same folder).
As stated in the answer, in order to use a non deprecated way to sign your own script, one should use New-SelfSignedCertificate.
Generate the key:
New-SelfSignedCertificate -DnsName email#yourdomain.com -Type CodeSigning -CertStoreLocation cert:\CurrentUser\My
Export the certificate without the private key:
Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0] -FilePath code_signing.crt
The [0] will make this work for cases when you have more than one certificate... Obviously make the index match the certificate you want to use... or use a way to filtrate (by thumprint or issuer).
Import it as Trusted Publisher
Import-Certificate -FilePath .\code_signing.crt -Cert Cert:\CurrentUser\TrustedPublisher
Import it as a Root certificate authority.
Import-Certificate -FilePath .\code_signing.crt -Cert Cert:\CurrentUser\Root
Sign the script (assuming here it's named script.ps1, fix the path accordingly).
Set-AuthenticodeSignature .\script.ps1 -Certificate (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)
Obviously once you have setup the key, you can simply sign any other scripts with it.
You can get more detailed information and some troubleshooting help in this article.
It's fairly easy using the New-SelfSignedCertificate command in Powershell.
Open powershell and run these 3 commands.
Create certificate:
$cert = New-SelfSignedCertificate -DnsName www.yourwebsite.com -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My
Set the password for it:
$CertPassword = ConvertTo-SecureString -String "my_passowrd" -Force -AsPlainText
Export it:
Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "d:\selfsigncert.pfx" -Password $CertPassword
Your certificate selfsigncert.pfx will be located # D:/
Optional step: You would also require to add certificate password to system environment variables. do so by entering below in cmd:
setx CSC_KEY_PASSWORD "my_password"
Roger's answer was very helpful.
I had a little trouble using it, though, and kept getting the red "Windows can't verify the publisher of this driver software" error dialog. The key was to install the test root certificate with
certutil -addstore Root Demo_CA.cer
which Roger's answer didn't quite cover.
Here is a batch file that worked for me (with my .inf file, not included).
It shows how to do it all from start to finish, with no GUI tools at all
(except for a few password prompts).
REM Demo of signing a printer driver with a self-signed test certificate.
REM Run as administrator (else devcon won't be able to try installing the driver)
REM Use a single 'x' as the password for all certificates for simplicity.
PATH %PATH%;"c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin";"c:\Program Files\Microsoft SDKs\Windows\v7.0\Bin";c:\WinDDK\7600.16385.1\bin\selfsign;c:\WinDDK\7600.16385.1\Tools\devcon\amd64
makecert -r -pe -n "CN=Demo_CA" -ss CA -sr CurrentUser ^
-a sha256 -cy authority -sky signature ^
-sv Demo_CA.pvk Demo_CA.cer
makecert -pe -n "CN=Demo_SPC" -a sha256 -cy end ^
-sky signature ^
-ic Demo_CA.cer -iv Demo_CA.pvk ^
-sv Demo_SPC.pvk Demo_SPC.cer
pvk2pfx -pvk Demo_SPC.pvk -spc Demo_SPC.cer ^
-pfx Demo_SPC.pfx ^
-po x
inf2cat /drv:driver /os:XP_X86,Vista_X64,Vista_X86,7_X64,7_X86 /v
signtool sign /d "description" /du "www.yoyodyne.com" ^
/f Demo_SPC.pfx ^
/p x ^
/v driver\demoprinter.cat
certutil -addstore Root Demo_CA.cer
rem Needs administrator. If this command works, the driver is properly signed.
devcon install driver\demoprinter.inf LPTENUM\Yoyodyne_IndustriesDemoPrinter_F84F
rem Now uninstall the test driver and certificate.
devcon remove driver\demoprinter.inf LPTENUM\Yoyodyne_IndustriesDemoPrinter_F84F
certutil -delstore Root Demo_CA
As of PowerShell 4.0 (Windows 8.1/Server 2012 R2) it is possible to make a certificate in Windows without makecert.exe.
The commands you need are New-SelfSignedCertificate and Export-PfxCertificate.
Instructions are in Creating Self Signed Certificates with PowerShell.
You can generate one in Visual Studio 2019, in the project properties. In the Driver Signing section, the Test Certificate field has a drop-down. Generating a test certificate is one of the options. The certificate will be in a file with the 'cer' extension typically in the same output directory as your executable or driver.
This post will only answer the "how to sign an EXE file if you have the crtificate" part:
To sign the exe file, I used MS "signtool.exe". For this you will need to download the bloated MS Windows SDK which has a whooping 1GB. FORTUNATELY, you don't have to install it. Just open the ISO and extract "Windows SDK Signing Tools-x86_en-us.msi". It has a merely 400 KB.
Then I built this tiny script file:
prompt $
echo off
cls
copy "my.exe" "my.bak.exe"
"c:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe" sign /fd SHA256 /f MyCertificate.pfx /p MyPassword My.exe
pause
Details
__