Cross-Platform Certificate Encrypted Strings
Password vaulting solves a very real problem: how do we leverage automation and avoid hardcoding passwords in source? We can use products like Hashicorp’s Vault to provide RBAC, password expirations, and other advanced functionality that can plug into automation but this introduces a new problem - how do we protect that “first secret” that allows the newly built server to access and authenticate with the vault? We could set this password in plaintext/source - but that’s the problem that vaulting attempts to solve.
One potential solution is to leverage CMS messages. The Cryptographic Message Syntax is a standardized method for signing, encrypting, decrypting, and validating any form of digital data using certificate-based key pairs.
A certificate must have extensions and usage that specifies document encryption in order decrypt/encrypt CMS messages. On Windows, this certificate resides in a certificate store on the local system - this certificate store is protected with a combination of ACL and the Windows Data Protection API. On Linux, the private key can be protected via folder and file permissions.
If the existing VM automation relies upon vRA, vRO, binary artifact repository and source repository - one potential usage for CMS messages to solve the “First Secret” problem is as follows:
- A new VM either has the certificate burned in to the template, or the certificate can be stored in vRO and injected into VMs at deployment time.
- The CMS message containing the “first secret” can be made available in source or binary repositories.
- At the opportune time, the VM will retrieve the CMS message, decrypt with the certificate and use this credential to auth with the desired password vaulting software.
- After the VM successfully authenticates and before the VM is handed off, vRO can forcibly remove the certificate from the VM to reduce exposure.
Create the Certificate (Windows / PowerShell)
- Manually create certificate with an inf file and certreq:
- Create certreq.inf file for cert request (example below). Most things can be changed, but
szOID_ENHANCED_KEY_USAGE
,szOID_DOCUMENT_ENCRYPTION
,KeyUsage
, and the[Extensions]
fields should be left as is.[Version] Signature = "$Windows NT$" [Strings] szOID_ENHANCED_KEY_USAGE = "2.5.29.37" szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1" [NewRequest] Subject = "[email protected]" MachineKeySet = false KeyLength = 8192 KeySpec = AT_KEYEXCHANGE HashAlgorithm = Sha1 Exportable = true RequestType = Cert KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE" ValidityPeriod = "Years" ValidityPeriodUnits = "1" [Extensions] %szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_DOCUMENT_ENCRYPTION%"
-
Create a new private/public key pair:
C:\> Certreq -new c:\path\to\certreq.inf output.cert
- Create certreq.inf file for cert request (example below). Most things can be changed, but
- Alternatively, create it with powershell:
C:\> New-SelfSignedCertificate -Subject "[email protected]" -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsage KeyEncipherment,DataEncipherment, KeyAgreement -Type DocumentEncryptionCert
Export Certificate to Linux
- Export the certificate and private key pair with PowerShell
C:\> $MyPassword = ConvertTo-SecureString -String "exportpassword" -Force -AsPlainText C:\> (Get-ChildItem -path Cert:\CurrentUser\My\).Where({$_.Subject -eq "[email protected]"}) | Export-PfxCertificate -FilePath c:\temp\mypfx.pfx -Password $MyPassword
- On the Linux server, convert the pfx and remove the password
- Convert the entire pfx to a pem file
~/> openssl pkcs12 -in mypfx.pfx -out all.pem Enter Import Password: [exportpassword] MAC verified OK Enter PEM pass phrase: [exportpassword] Verifying - Enter PEM pass phrase: [exportpassword]
- Export key into rsa format
~/> openssl rsa -in all.pem -out rsa.key Enter pass phrase for all.pem: [exportpassword] writing RSA key
- This will result in two files:
all.pem
andrsa.key
.
- Convert the entire pfx to a pem file
Encryption!
- Encrypt your secret:
- Windows
- Command:
C:\> Protect-CmsMessage -Content "SecretPassword1!" -To *[email protected] -----BEGIN CMS----- MIIBuQYJKoZIhvcNAQcDoIIBqjCCAaYCAQAxggFRMIIBTQIBADA1MCExHzAdBgNVBAMMFmNlcnRl bmNAbWFzdGVyY2FyZC5jb20CEDtwj/MAVhipS6fXV2mKPRgwDQYJKoZIhvcNAQEHMAAEggEAqdy6 BJ3F2zkCw0s1wwRXyfZ6LO5C/DldszJi9o5jodwh75pmbCkd+sOfU2XwIVSfbzYdgEuwpKqpoDFJ ykbuskBI9zqCXEDrWLSksRr9UfBdM4lToZR58IIhKhe7d6PU1YCvXcGM2zF2MzE1lPJHl8q9O24c EHxvz1OHaVcLnhZ+bxOfOhTbidiEr5DwTrL69gChWCAf4Yv6EUzacEsO08+A0kvWRBiwmtBSnprl 6mJW4pgPZN6qgxSBJafswv5AS3X+9/bIyNoyNIwD3o5ZcEJ5CtZa2YGW6P1n1EMyOSeDndC8sxj1 VWydE3aJ6aZwcI0P6Ifv38wjUNV/Wbs/HzBMBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAPgGSD tSj98L7jJLdlRpTxgCB6BfCAEwR8hQx9CyfbpfRTqgEFLsxHn76IgRWUvA5e8A== -----END CMS-----
- The output can be captured to a plaintext file by adding the Out-File cmdlet:
C:\> Protect-CmsMessage -Content "SecretPassword1!" -To *[email protected] | Out-File -Path C:\Temp\encrypted.enc
- Command:
- Linux
- Command:
~/> openssl cms -encrypt -from demo@localhost -to [email protected] -subject "encrypted" -out encrypted.enc -outform PEM all.pem SecretPassword1! [ctrl]-[d]
- This results in a mail.msg file like below
~/> cat encrypted.enc -----BEGIN CMS----- MIIBqAYJKoZIhvcNAQcDoIIBmTCCAZUCAQAxggFRMIIBTQIBADA1MCExHzAdBgNV BAMMFmNlcnRlbmNAbWFzdGVyY2FyZC5jb20CEDtwj/MAVhipS6fXV2mKPRgwDQYJ KoZIhvcNAQEBBQAEggEABPSASeNou8YBTjaEe3s+buvZwJuw7pGpLh3Hu2bsve+b +gTzoZuPAeLPR1LhAQVJiBXxSJUyGNemviehSgndOKYFWhojQnnncB/i/nin5ijk uBzuXgcFBEJDvFqtD8IsXGkLdwa2D7nuELpqd5rZXGE9GjMSFVtkK2gsczKE1Rza URVNGcWt94QgPQvx4xk1svp7wRgkBIOi+1nmXQ5r1kdS70gz6Z1pV9xanu5KhPyb fn8EwyzYoNiEsheFaSzstJCUOYiQckXjY/i/aSezrYM9PDPefCZqIIsTLQlAbi+c qhN5jPs4utMVpFDnT5oHG8ObsJQjGFKmpjbKRiWv8DA7BgkqhkiG9w0BBwEwFAYI KoZIhvcNAwcECEjEr1W2znlsgBgwF9+IDrrHEqStVkMkCMrO/PnpcM5dLIY= -----END CMS-----
- Command:
- Windows
Decryption!
- Decrypt your secret
- Windows
- Obtain or create a file with the CMS message content
C:\> $Content = @" >> -----BEGIN CMS----- >> MIIBqAYJKoZIhvcNAQcDoIIBmTCCAZUCAQAxggFRMIIBTQIBADA1MCExHzAdBgNV >> BAMMFmNlcnRlbmNAbWFzdGVyY2FyZC5jb20CEDtwj/MAVhipS6fXV2mKPRgwDQYJ >> KoZIhvcNAQEBBQAEggEABPSASeNou8YBTjaEe3s+buvZwJuw7pGpLh3Hu2bsve+b >> +gTzoZuPAeLPR1LhAQVJiBXxSJUyGNemviehSgndOKYFWhojQnnncB/i/nin5ijk >> uBzuXgcFBEJDvFqtD8IsXGkLdwa2D7nuELpqd5rZXGE9GjMSFVtkK2gsczKE1Rza >> URVNGcWt94QgPQvx4xk1svp7wRgkBIOi+1nmXQ5r1kdS70gz6Z1pV9xanu5KhPyb >> fn8EwyzYoNiEsheFaSzstJCUOYiQckXjY/i/aSezrYM9PDPefCZqIIsTLQlAbi+c >> qhN5jPs4utMVpFDnT5oHG8ObsJQjGFKmpjbKRiWv8DA7BgkqhkiG9w0BBwEwFAYI >> KoZIhvcNAwcECEjEr1W2znlsgBgwF9+IDrrHEqStVkMkCMrO/PnpcM5dLIY= >> -----END CMS----- >> "@
- Decrypt with the Unprotect-CmsMessage cmdlet
language-powershell C:\> Unprotect-CmsMessage -Content $content SecretPassword1!
`
- Obtain or create a file with the CMS message content
- Linux
- Obtain or create a file with the CMS message content
~/> echo " -----BEGIN CMS----- MIIBuQYJKoZIhvcNAQcDoIIBqjCCAaYCAQAxggFRMIIBTQIBADA1MCExHzAdBgNVBAMMFmNlcnRl bmNAbWFzdGVyY2FyZC5jb20CEDtwj/MAVhipS6fXV2mKPRgwDQYJKoZIhvcNAQEHMAAEggEAqdy6 BJ3F2zkCw0s1wwRXyfZ6LO5C/DldszJi9o5jodwh75pmbCkd+sOfU2XwIVSfbzYdgEuwpKqpoDFJ ykbuskBI9zqCXEDrWLSksRr9UfBdM4lToZR58IIhKhe7d6PU1YCvXcGM2zF2MzE1lPJHl8q9O24c EHxvz1OHaVcLnhZ+bxOfOhTbidiEr5DwTrL69gChWCAf4Yv6EUzacEsO08+A0kvWRBiwmtBSnprl 6mJW4pgPZN6qgxSBJafswv5AS3X+9/bIyNoyNIwD3o5ZcEJ5CtZa2YGW6P1n1EMyOSeDndC8sxj1 VWydE3aJ6aZwcI0P6Ifv38wjUNV/Wbs/HzBMBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAPgGSD tSj98L7jJLdlRpTxgCB6BfCAEwR8hQx9CyfbpfRTqgEFLsxHn76IgRWUvA5e8A== -----END CMS----- " > encrypted.enc
- Decrypt with the openssl cms executable
~/> openssl cms -decrypt -in encrypted.enc -recip all.pem -inkey rsa.key -inform PEM SecretPassword1!%
- Note that openssl seems to add a ‘
%
’ to the end of the string.
- Obtain or create a file with the CMS message content
- Windows
- This string can now be used in scripts/credentials/other operations