How to request a exportable certificate using PowerShell? - windows

Refer to Get-Certificate
I tried to request a certificate using PowerShell, it worked but the certificate is not exportable, here is my command:
Get-Certificate -Template "MyComputer" -SubjectName "CN=corey.com" -CertStoreLocation cert:\LocalMachine\My
When I try to export the certificate, it failed.
Export-PfxCertificate -Cert cert:\LocalMachine\My\$Thumbprint -FilePath C:\corey.com.pfx -Password $mypwd
The error message:
Export-PfxCertificate: Cannot export non-exportable private key.
I can't find any parameter like Exportable or property for me to use with Get-Certificate command. Is there any way to request/make a certificate exportable by using PowerShell?

Cause there is no parameter to make it exportable when using Get-Certificate, so I use certreq as a replacement to achieve my goal and post here hoping that could help someone else.
Firstly, prepare an information file, and set Exportable as TRUE.
$file = #'
[NewRequest]
Subject = "CN=corey.com"
KeyLength = 2048
Exportable = TRUE
[RequestAttributes]
CertificateTemplate = "MyTemplate"
'#
Set-Content temp.inf $file
Secondly, type the following commands.
# create a new request from an .inf file
certreq -new temp.inf temp.req
# submit a request to the certificate authority
certreq -submit -config CAHostName\CAName temp.req temp.cer
# accept and install a response to a certificate request
certreq -accept temp.cer
Finally, export the certificate and assign a password for it.
$mypwd = ConvertTo-SecureString -String $password -Force -AsPlainText
Export-PfxCertificate -Cert cert:\LocalMachine\My\$Thumbprint -FilePath C:\corey.com.pfx -Password $mypwd
For more details, please see certreq - Microsoft Docs

Related

Add Windows Credentials using PowerShell & cmdkey

I am trying to use credentials from some UI prompted to add Windows credentials using cmdkey:
$sessionCredential = $host.ui.PromptForCredential("Need credentials", "Please enter your user name and password.", "", "Server Crdentials")
$ps = ConvertFrom-SecureString -SecureString $sessionCredential.password
cmdkey.exe /add:server1 /user:$($sessionCredential.UserName) /pass:$($ps)
The credentials are added correctly, but the password is not.
What can I do?
Use the CredentialManager PowerShell module. It saves the password in the same place as cmdkey, but it can take PSCredential objects directly without needing to convert to text.
Import-Module CredentialManager
# Get the credential from the user with a windows credentials prompt:
$SessionCredential = Get-Credential -Message 'Please enter your server credentials'
# Save the credential object directly without unwrapping it:
New-StoredCredential -Credentials $SessionCredential -Target ServerCredentials -Persist Enterprise `
-Comment "Server Credentials for $($SessionCredential.UserName)" > $null
# Open the credential later
$SavedCred = Get-StoredCredential -Target ServerCredentials
# Delete if needed
Remove-StoredCredential -Target ServerCredentials
cmdkey /pass:$($ps) is prone to errors due to PowerShell garbling password characters.
Apparently, the problem is ConvertFrom-SecureString is returning an encrypted standard string, ConvertFrom-SecureString.
And the option to get plain text is not available on PowerShell 5.1.
I found the correct convert here.
I understand it is not secured. It is used inside secured clients.
See fixed code below:
$sessionCredential = $host.ui.PromptForCredential("Need credentials", "Please enter your user name and password.", "", "Server Crdentials")
$mpass = [System.Net.NetworkCredential]::new("",$sessionCredential.password).Password
cmdkey.exe /add:server1 /user:$($sessionCredential.UserName) /pass:$($mpass)
Cpt.Whale's answer worked like a charm. The only caveat was the need to copy/distribute the CredentialManager module before using it.

Add-AzVMSshPublicKey to vmConfig fails when calling New-AzVM

I'm following the windows quickstart for creating a VM in azure powershell
I'm stuck here:
# Configure the SSH key
$sshPublicKey = cat ~/.ssh/id_rsa.pub
Add-AzVMSshPublicKey `
-VM $vmconfig `
-KeyData $sshPublicKey `
-Path "/home/azureuser/.ssh/authorized_keys"
First of all I think the following code is wrong, as cat returns System.String[] and running this verbatim results in
Add-AzVMSshPublicKey : Cannot convert 'System.Object[]' to the type 'System.String'
So... I instead use Get-Content "./path/to/file" -raw which just returns a string and the command runs without errors
Now when I run
New-AzVM `
-ResourceGroupName $resourceGroupName `
-Location $location -VM $vmConfig
I get the following error, meaning the keyData I set earlier wasn't set correctly.
New-AzVM : The value of parameter linuxConfiguration.ssh.publicKeys.keyData is invalid.
I've found the issue - So Azure key vault gives me a PEM public key in the form
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAO...
...
...
...
...0CS94AFAgMBAAE=
-----END PUBLIC KEY-----
Whereas the VM is expecting it in OpenSSH format
ssh-rsa ..........
I've tried to convert it with
ssh-keygen -i -m PKCS8 -f ./key.pem
but nothing gets output
UPDATE
Aaaand it's a powershell issue
First, the tutorial is a guide to create Linux VM via Azure PowerShell, not Windows. Second, the command cat just outputs the content of the file. And command $sshPublicKey = cat ~/.ssh/id_rsa.pub creates a variable in string:
The parameter -KeyData of the command Add-AzVMSshPublicKey also expect a string:
So there is no problem with the PowerShell command and all the commands work fine on my side. And the error shows the value of the key data is invalid, what you need to do is to make sure if the SSH public key is no problem.
To get this key from an Azure Key vault,
Get-AzKeyVaultKey -OutFile *filename* returns a public key in PEM Form
-----BEGIN PUBLIC KEY------
....
-----END PUBLIC KEY-----
The vm requires the key data to be a one-liner in OpenSSH format
ssh-rsa ....... mykeylabel
But Powershell's ssh-keygen, unlike its UNIX counterpart, cannot convert between these formats as it has an open bug

How to add more than one machine to the trusted hosts list using winrm

To run powershell commands on a machine from a remote machine we have to add the remote machine to the trusted hosts list of the host machine.
I am adding machine A to machine B's trusted hosts using the following command :
winrm set winrm/config/client ‘#{TrustedHosts="machineA"}’
How to add more machines say machine C, machine D to trusted hosts list of machine B?
I prefer to work with the PSDrive WSMan:\.
Get TrustedHosts
Get-Item WSMan:\localhost\Client\TrustedHosts
Set TrustedHosts
provide a single, comma-separated, string of computer names
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'machineA,machineB'
or (dangerous) a wild-card
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*'
to append to the list, the -Concatenate parameter can be used
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'machineC' -Concatenate
winrm set winrm/config/client '#{TrustedHosts="machineA,machineB"}'
The suggested answer by Loïc MICHEL blindly writes a new value to the TrustedHosts entry.
I believe, a better way would be to first query TrustedHosts.
As Jeffery Hicks posted in 2010, first query the TrustedHosts entry:
PS C:\> $current=(get-item WSMan:\localhost\Client\TrustedHosts).value
PS C:\> $current+=",testdsk23,alpha123"
PS C:\> set-item WSMan:\localhost\Client\TrustedHosts –value $current
I created a module to make dealing with trusted hosts slightly easier, psTrustedHosts. You can find the repo here on GitHub. It provides four functions that make working with trusted hosts easy: Add-TrustedHost, Clear-TrustedHost, Get-TrustedHost, and Remove-TrustedHost. You can install the module from PowerShell Gallery with the following command:
Install-Module psTrustedHosts -Force
In your example, if you wanted to append hosts 'machineC' and 'machineD' you would simply use the following command:
Add-TrustedHost 'machineC','machineD'
To be clear, this adds hosts 'machineC' and 'machineD' to any hosts that already exist, it does not overwrite existing hosts.
The Add-TrustedHost command supports pipeline processing as well (so does the Remove-TrustedHost command) so you could also do the following:
'machineC','machineD' | Add-TrustedHost
Same as #Altered-Ego but with txt.file:
Get-Content "C:\ServerList.txt"
machineA,machineB,machineC,machineD
$ServerList = Get-Content "C:\ServerList.txt"
$currentTrustHost=(get-item WSMan:\localhost\Client\TrustedHosts).value
if ( ($currentTrustHost).Length -gt "0" ) {
$currentTrustHost+= ,$ServerList
set-item WSMan:\localhost\Client\TrustedHosts –value $currentTrustHost -Force -ErrorAction SilentlyContinue
}
else {
$currentTrustHost+= $ServerList
set-item WSMan:\localhost\Client\TrustedHosts –value $currentTrustHost -Force -ErrorAction SilentlyContinue
}
The "-ErrorAction SilentlyContinue" is required in old PS version to avoid fake error message:
PS C:\Windows\system32> get-item WSMan:\localhost\Client\TrustedHosts
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client
Type Name SourceOfValue Value
---- ---- ------------- -----
System.String TrustedHosts machineA,machineB,machineC,machineD
winrm set winrm/config/client '#{TrustedHosts="ServerA"}'
Generates this error:
Syntax Error: input must be of the form {KEY="VALUE"[;KEY="VALUE"]}
This worked for me (Server 2016):
winrm set winrm/config/client #{TrustedHosts="ServerA"}

Add Mozilla root certs to Windows without admin

I want to add Mozilla's root certs to Windows 7 without admin privileges.
Is there a straight forward way to add the root certificates into the current user's certificate store? I'd prefer to use Windows' native tools, without relying on something I'd have to download.
Some resources that looked promising.
Pre-converted PEM files by CURL - The Mozilla root certs converted to PEM and hosted by cURL. Here's a direct link to the PEM Encoded root certs
Verified HTTPs in Ruby - A general overview of how to obtain the root certificates.
How to get root certs for cURL - explains how to generate the PEM file from the Mozilla certificates yourself.
How to Import Certificates using Powershell - a ranting overview of how to install certificates that seems more complex than it ought to be.
I ended making a powershell script to do it.
VERIFY THIS CODE BEFORE RUNNING IT. It's adding all of the certificate authorities from http://curl.haxx.se/ca/cacert.pem to the current user's TRUSTED ROOT certificate store.
To run it in a single command, paste the following into a command prompt:
#powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.github.com/jschaf/install-mozilla-certs/master/install-mozilla-cert.ps1'))"
Here's the Github link: https://github.com/jschaf/install-mozilla-certs
And the source:
# Variables
$url = "http://curl.haxx.se/ca/cacert.pem"
# Download the certificates
Write-Host "Downloading Mozilla certificates from $url."
$downloader = New-Object System.Net.WebClient
$rawcerts = $downloader.DownloadString("http://curl.haxx.se/ca/cacert.pem")
# Remove headers and begin/end delimiters and convert into a byte
# stream
$header = "-----BEGIN CERTIFICATE-----`n"
$footer = "`n-----END CERTIFICATE-----"
$match_string = "(?s)$header(.*?)$footer"
$certs_matches = Select-String $match_string -input $rawcerts -AllMatches
$certs_base64 = $certs_matches.matches | %{ $_.Groups[1].Value }
$certs_bytes = $certs_base64 | %{ ,[System.Text.Encoding]::UTF8.GetBytes($_) }
# Install the certificates
$user_root_cert_store = Get-Item Cert:\CurrentUser\Root
$user_root_cert_store.Open("ReadWrite")
foreach ($c in $certs_bytes) {
$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2(,$c)
$user_root_cert_store.Add($cert)
}
$user_root_cert_store.Close()
Write-Host "Finished installing all certificates."
One annoying thing is that Windows will prompt for yes/no for every certificate. Since it's installing 158 certificates this gets old quick. If anyone knows how to prevent confirmation let me know or drop a pull request.

Unable to load config info from /usr/local/ssl/openssl.cnf on Windows

While using OpenSSL on Windows:
openssl genrsa -out privatekey.pem 1024 -->
Created successfully
openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 365
---->
Showing error message as
unable to load config info from /usr/local/ssl/openssl.cnf
After installing OpenSSL I was required to create a new environment variable:
Name: OPENSSL_CONF
Value: C:\Program Files\OpenSSL\openssl.cnf
In powershell:
$env:OPENSSL_CONF = "${env:ProgramFiles}\OpenSSL\openssl.cnf"
This value differs from previous installation versions (as seen in a previous edit of this post). Also, don't forget to add the openssl binary folder ${env:ProgramFiles}\OpenSSL to your Path.
You should specify the absolute path to the config, something like this:
openssl req -x509 -config "C:\OpenSSL-Win64\bin\openssl.cnf" ...
In Windows 10, no need to restart nor run in Administrator's mode but instead set openssl config like so:
set OPENSSL_CONF=C:\Program Files (x86)\GnuWin32\share\openssl.cnf
Of course, if you are using GnuWin32
The only thing that worked for me in this situation was the self-created openssl.cnf file.
Here are the basics needed for this exercise (edit as needed):
#
# OpenSSL configuration file.
#
# Establish working directory.
dir = .
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = $dir/serial
database = $dir/certindex.txt
new_certs_dir = $dir/certs
certificate = $dir/cacert.pem
private_key = $dir/private/cakey.pem
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = md5 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
# Variable name Prompt string
#------------------------- ----------------------------------
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (department, division)
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name (city, district)
stateOrProvinceName = State or Province Name (full name)
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
# Default values for the above, for consistency and less typing.
# Variable name Value
#------------------------ ------------------------------
0.organizationName_default = My Company
localityName_default = My Town
stateOrProvinceName_default = State or Providence
countryName_default = US
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
I hope that helps.
In windows , [Similar scenario]
I was facing the same problem But It was during requesting for Certificate Signing Request.
I did the below , It Worked for me.
Once OpenSSL installed, Ran command prompt as administrator after the system reboot.[for the best I did both.. run as admin and system reboot]
did,
1.[Error Case]
C:\OpenSSL-Win64\bin>openssl req -new -key server.key -out server.csr
WARNING: can't open config file: C:\OpenSSL-Win64\bin\openssl.cnf
AND
Unable to load config info from C:\OpenSSL-Win64\bin\openssl.cnf
2.[Worked with Warning]
C:\OpenSSL-Win64\bin> openssl req -new -key server.key -out server.csr -config C:\OpenSSL-Win64\bin\openssl.cfg
[Warning message]: WARNING: can't open config file: C:\OpenSSL-Win64\bin\openssl.cnf
But prompted me for the Pass Phrase for server.key
It worked for me.
I referred,This link for my assistance.
Thank you.
For me on Windows 8, I simply found openssl.cnf file and copied it on the C drive. then:
openssl req -new -key server.key -out server.csr -config C:\openssl.cnf
Worked perfectly.
After installing OpenSSL, you need to restart your computer and use Run As Administrator. Then its works.
With the GnuWin32 tools I found the openssl.cnf under C:\gnuwin32\share
set OPENSSL_CONF=C:\gnuwin32\share\openssl.cnf
In my case, I need to set the path of openssl.cnf file manually on the command using config option. So the command
openssl req -x509 -config "C:\Users\sk\Downloads\openssl-0.9.8k_X64\openssl.cnf" -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 900
In Windows 7 I didn't have to restart, simply run command prompt in administrator mode.
If you're using Win32 OpenSSL v1.1.0g, setting up this environment variable:
set OPENSSL_CONF=C:\OpenSSL-Win32\bin\cnf\openssl.cnf
Before running this command with "server.key", successfully creating "server.csr":
openssl req -new -key server.key -out server.csr
On the basic question of why openssl is not found:
Short answer:Some installation packages for openssl have a default openssl.cnf pre-included. Other packages do not.
In the latter case you will include one from the link shown below;
You can enter additional user-specifics --DN name,etc-- as needed.
From https://www.openssl.org/docs/manmaster/man5/config.html,I quote directly:
"OPENSSL LIBRARY CONFIGURATION
Applications can automatically configure certain aspects of OpenSSL using the master OpenSSL configuration file, or optionally an alternative configuration file. The openssl utility includes this functionality: any sub command uses the master OpenSSL configuration file unless an option is used in the sub command to use an alternative configuration file.
To enable library configuration the default section needs to contain an appropriate line which points to the main configuration section. The default name is openssl_conf which is used by the openssl utility. Other applications may use an alternative name such as myapplication_conf. All library configuration lines appear in the default section at the start of the configuration file.
The configuration section should consist of a set of name value pairs which contain specific module configuration information. The name represents the name of the configuration module. The meaning of the value is module specific: it may, for example, represent a further configuration section containing configuration module specific information. E.g.:"
So it appears one must self configure openssl.cnf according to your
Distinguished Name (DN), along with other entries specific to your use.
Here is the template file from which you can generate openssl.cnf
with your specific entries.
One Application actually has a demo installation that includes a demo .cnf file.
Additionally, if you need to programmatically access .cnf files, you can
include appropriate headers --openssl/conf.h-- and parse your .cnf files
using
CONF_modules_load_file(const char *filename, const char *appname,
unsigned long flags);
Here are docs for "CONF_modules_load_file";
On Windows Powershell:
$env:OPENSSL_CONF = "${env:ProgramFiles}\OpenSSL-Win64\bin\openssl.cfg"
For me put variable before calling did the trick:
OPENSSL_CONF=/usr/ssl/openssl.cnf openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 365
I had similar problem on Windows 7:
WARNING: can't open config file: C:\OpenSSL-Win32\bin\openssl.cfg
Unable to load config info from C:\OpenSSL-Win32\bin\openssl.cfg
The reason was removed OpenSSL-Win32 directory without using deinstallator, so not all components was properly removed from system.
I had to remove environment variable OPENSSL_CONF manually.
Some openssl binaries, e.g. installed with git, does not need OPENSSL_CONF environment variable, but if this environment variable exists it must lead to valid file.

Resources