win_certificate_store: added new module (#33980)

* win_certificate_store: added new module

* added warning about become or credssp for pfx
pull/34596/head
Jordan Borean 7 years ago committed by GitHub
parent 34206a0402
commit b2a415daae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,252 @@
#!powershell
# This file is part of Ansible
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
$ErrorActionPreference = "Stop"
$store_name_values = ([System.Security.Cryptography.X509Certificates.StoreName]).GetEnumValues()
$store_location_values = ([System.Security.Cryptography.X509Certificates.StoreLocation]).GetEnumValues()
$params = Parse-Args $args -supports_check_mode $true
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "absent", "exported", "present"
$path = Get-AnsibleParam -obj $params -name "path" -type "path" -failifempty ($state -eq "present" -or $state -eq "exported")
$thumbprint = Get-AnsibleParam -obj $params -name "thumbprint" -type "str" -failifempty ($state -eq "exported")
$store_name = Get-AnsibleParam -obj $params -name "store_name" -type "str" -default "My" -validateset $store_name_values
$store_location = Get-AnsibleParam -obj $params -name "store_location" -type "str" -default "LocalMachine" -validateset $store_location_values
$password = Get-AnsibleParam -obj $params -name "password" -type "str"
$key_exportable = Get-AnsibleParam -obj $params -name "key_exportable" -type "bool" -default $true
$key_storage = Get-AnsibleParam -obj $param -name "key_storage" -type "str" -default "default" -validateset "default", "machine", "user"
$file_type = Get-AnsibleParam -obj $params -name "file_type" -type "str" -default "der" -validateset "der", "pem", "pkcs12"
$result = @{
changed = $false
thumbprints = @()
}
Function Get-CertFile($path, $password, $key_exportable, $key_storage) {
# parses a certificate file and returns X509Certificate2Collection
if (-not (Test-Path -Path $path -PathType Leaf)) {
Fail-Json -obj $result -message "File at '$path' either does not exist or is not a file"
}
# must set at least the PersistKeySet flag so that the PrivateKey
# is stored in a permanent container and not deleted once the handle
# is gone.
$store_flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
$key_storage = $key_storage.substring(0,1).ToUpper() + $key_storage.substring(1).ToLower()
$store_flags = $store_flags -bor [Enum]::Parse([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags], "$($key_storage)KeySet")
if ($key_exportable) {
$store_flags = $store_flags -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
}
# TODO: If I'm feeling adventurours, write code to parse PKCS#12 PEM encoded
# file as .NET does not have an easy way to import this
$certs = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2Collection
try {
$certs.Import($path, $password, $store_flags)
} catch {
Fail-Json -obj $result -message "Failed to load cert from file: $($_.Exception.Message)"
}
return $certs
}
Function New-CertFile($cert, $path, $type, $password) {
$content_type = switch ($type) {
"pem" { [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert }
"der" { [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert }
"pkcs12" { [System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12 }
}
if ($type -eq "pkcs12") {
$missing_key = $false
if ($cert.PrivateKey -eq $null) {
$missing_key = $true
} elseif ($cert.PrivateKey.CspKeyContainerInfo.Exportable -eq $false) {
$missing_key = $true
}
if ($missing_key) {
Fail-Json -obj $result -message "Cannot export cert with key as PKCS12 when the key is not marked as exportable or not accesible by the current user"
}
}
if (Test-Path -Path $path) {
Remove-Item -Path $path -Force
$result.changed = $true
}
try {
$cert_bytes = $cert.Export($content_type, $password)
} catch {
Fail-Json -obj $result -message "Failed to export certificate as bytes: $($_.Exception.Message)"
}
# Need to manually handle a PEM file
if ($type -eq "pem") {
$cert_content = "-----BEGIN CERTIFICATE-----`r`n"
$base64_string = [System.Convert]::ToBase64String($cert_bytes, [System.Base64FormattingOptions]::InsertLineBreaks)
$cert_content += $base64_string
$cert_content += "`r`n-----END CERTIFICATE-----"
$file_encoding = [System.Text.Encoding]::ASCII
$cert_bytes = $file_encoding.GetBytes($cert_content)
} elseif ($type -eq "pkcs12") {
$result.key_exported = $false
if ($cert.PrivateKey -ne $null) {
$result.key_exportable = $cert.PrivateKey.CspKeyContainerInfo.Exportable
}
}
if (-not $check_mode) {
try {
[System.IO.File]::WriteAllBytes($path, $cert_bytes)
} catch [System.ArgumentNullException] {
Fail-Json -obj $result -message "Failed to write cert to file, cert was null: $($_.Exception.Message)"
} catch [System.IO.IOException] {
Fail-Json -obj $result -message "Failed to write cert to file due to IO exception: $($_.Exception.Message)"
} catch [System.UnauthorizedAccessException, System>Security.SecurityException] {
Fail-Json -obj $result -message "Failed to write cert to file due to permission: $($_.Exception.Message)"
} catch {
Fail-Json -obj $result -message "Failed to write cert to file: $($_.Exception.Message)"
}
}
$result.changed = $true
}
Function Get-CertFileType($path, $password) {
$certs = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2Collection
try {
$certs.Import($path, $password, 0)
} catch [System.Security.Cryptography.CryptographicException] {
# the file is a pkcs12 we just had the wrong password
return "pkcs12"
} catch {
return "unknown"
}
$file_contents = Get-Content -Path $path -Raw
if ($file_contents.StartsWith("-----BEGIN CERTIFICATE-----")) {
return "pem"
} elseif ($file_contents.StartsWith("-----BEGIN PKCS7-----")) {
return "pkcs7-ascii"
} elseif ($certs.Count -gt 1) {
# multiple certs must be pkcs7
return "pkcs7-binary"
} elseif ($certs[0].HasPrivateKey) {
return "pkcs12"
} elseif ($path.EndsWith(".pfx") -or $path.EndsWith(".p12")) {
# no way to differenciate a pfx with a der file so we must rely on the
# extension
return "pkcs12"
} else {
return "der"
}
}
$store_name = [System.Security.Cryptography.X509Certificates.StoreName]::$store_name
$store_location = [System.Security.Cryptography.X509Certificates.Storelocation]::$store_location
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $store_name, $store_location
try {
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
} catch [System.Security.Cryptography.CryptographicException] {
Fail-Json -obj $result -message "Unable to open the store as it is not readable: $($_.Exception.Message)"
} catch [System.Security.SecurityException] {
Fail-Json -obj $result -message "Unable to open the store with the current permissions: $($_.Exception.Message)"
} catch {
Fail-Json -obj $result -message "Unable to open the store: $($_.Exception.Message)"
}
$store_certificates = $store.Certificates
try {
if ($state -eq "absent") {
$cert_thumbprints = @()
if ($path -ne $null) {
$certs = Get-CertFile -path $path -password $password -key_exportable $key_exportable -key_storage $key_storage
foreach ($cert in $certs) {
$cert_thumbprints += $cert.Thumbprint
}
} elseif ($thumbprint -ne $null) {
$cert_thumbprints += $thumbprint
} else {
Fail-Json -obj $result -message "Either path or thumbprint must be set when state=absent"
}
foreach ($cert_thumbprint in $cert_thumbprints) {
$result.thumbprints += $cert_thumbprint
$found_certs = $store_certificates.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint, $cert_thumbprint, $false)
if ($found_certs.Count -gt 0) {
foreach ($found_cert in $found_certs) {
try {
if (-not $check_mode) {
$store.Remove($found_cert)
}
} catch [System.Security.SecurityException] {
Fail-Json -obj $result -message "Unable to remove cert with thumbprint '$cert_thumbprint' with the current permissions: $($_.Exception.Message)"
} catch {
Fail-Json -obj $result -message "Unable to remove cert with thumbprint '$cert_thumbprint': $($_.Exception.Message)"
}
$result.changed = $true
}
}
}
} elseif ($state -eq "exported") {
# TODO: Add support for PKCS7 and exporting a cert chain
$result.thumbprints += $thumbprint
$export = $true
if (Test-Path -Path $path -PathType Container) {
Fail-Json -obj $result -message "Cannot export cert to path '$path' as it is a directory"
} elseif (Test-Path -Path $path -PathType Leaf) {
$actual_cert_type = Get-CertFileType -path $path -password $password
if ($actual_cert_type -eq $file_type) {
try {
$certs = Get-CertFile -path $path -password $password -key_exportable $key_exportable -key_storage $key_storage
} catch {
# failed to load the file so we set the thumbprint to something
# that will fail validation
$certs = @{Thumbprint = $null}
}
if ($certs.Thumbprint -eq $thumbprint) {
$export = $false
}
}
}
if ($export) {
$found_certs = $store_certificates.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint, $thumbprint, $false)
if ($found_certs.Count -ne 1) {
Fail-Json -obj $result -message "Found $($found_certs.Count) certs when only expecting 1"
}
New-CertFile -cert $found_certs -path $path -type $file_type -password $password
}
} else {
$certs = Get-CertFile -path $path -password $password -key_exportable $key_exportable -key_storage $key_storage
foreach ($cert in $certs) {
$result.thumbprints += $cert.Thumbprint
$found_certs = $store_certificates.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint, $cert.Thumbprint, $false)
if ($found_certs.Count -eq 0) {
try {
if (-not $check_mode) {
$store.Add($cert)
}
} catch [System.Security.Cryptography.CryptographicException] {
Fail-Json -obj $result -message "Unable to import certificate with thumbprint '$($cert.Thumbprint)' with the current permissions: $($_.Exception.Message)"
} catch {
Fail-Json -obj $result -message "Unable to import certificate with thumbprint '$($cert.Thumbprint)': $($_.Exception.Message)"
}
$result.changed = $true
}
}
}
} finally {
$store.Close()
}
Exit-Json -obj $result

@ -0,0 +1,195 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of Ansible
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: win_certificate_store
version_added: '2.5'
short_description: Manages the certificate store
description:
- Used to import/export and remove certificates and keys from the local
certificate store.
- This module is not used to create certificates and will only manage existing
certs as a file or in the store.
- It can be used to import PEM, DER, P7B, PKCS12 (PFX) certificates and export
PEM, DER and PKCS12 certificates.
options:
state:
description:
- If C(present), will ensure that the certificate at I(path) is imported
into the certificate store specified.
- If C(absent), will ensure that the certificate specified by I(thumbprint)
or the thumbprint of the cert at I(path) is removed from the store
specified.
- If C(exported), will ensure the file at I(path) is a certificate
specified by I(thumbprint).
- When exporting a certificate, if I(path) is a directory then the module
will fail, otherwise the file will be replaced if needed.
default: present
choices:
- present
- absent
- exported
path:
description:
- The path to a certificate file.
- This is required when I(state) is C(present) or C(exported).
- When I(state) is C(absent) and I(thumbprint) is not specified, the
thumbprint is derived from the certificate at this path.
thumbprint:
description:
- The thumbprint as a hex string to either export or remove.
- See the examples for how to specify the thumbprint.
store_name:
description:
- The store name to use when importing a certificate or searching for a
certificate.
default: My
choices:
- AddressBook
- AuthRoot
- CertificateAuthority
- Disallowed
- My
- Root
- TrustedPeople
- TrustedPublisher
store_location:
description:
- The store location to use when importing a certificate or searching for a
certificate.
default: LocalMachine
choices:
- CurrentUser
- LocalMachine
password:
description:
- The password of the pkcs12 certificate key.
- This is used when reading a pkcs12 certificate file or the password to
set when C(state=exported) and C(file_type=pkcs12).
- If the pkcs12 file has no password set or no password should be set on
the exported file, do not set this option.
key_exportable:
description:
- Whether to allow the private key to be exported.
- If C(no), then this module and other process will only be able to export
the certificate and the private key cannot be exported.
- Used when C(state=present) only.
type: bool
default: 'yes'
key_storage:
description:
- Specifies where Windows will store the private key when it is imported.
- When set to C(default), the default option as set by Windows is used.
- When set to C(machine), the key is stored in a path accessible by various
users.
- When set to C(user), the key is stored in a path only accessible by the
current user.
- Used when C(state=present) only and cannot be changed once imported.
- See U(https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509keystorageflags.aspx)
for more details.
choices:
- default
- machine
- user
default: default
file_type:
description:
- The file type to export the certificate as when C(state=exported).
- C(der) is a binary ASN.1 encoded file.
- C(pem) is a base64 encoded file of a der file in the OpenSSL form.
- C(pkcs12) (also known as pfx) is a binary container that contains both
the certificate and private key unlike the other options.
- When C(pkcs12) is set and the private key is not exportable or accessible
by the current user, it will throw an exception.
choices:
- der
- pem
- pkcs12
default: der
notes:
- Some actions on PKCS12 certificates and keys may fail with the error
C(the specified network password is not correct), either use CredSSP or
Kerberos with credential delegation, or use C(become) to bypass these
restrictions.
- The certificates must be located on the Windows host to be set with I(path).
author:
- Jordan Borean (@jborean93)
'''
EXAMPLES = r'''
- name: import a certificate
win_certificate_store:
path: C:\temp\cert.pem
state: present
- name: import pfx certificate that is password protected
win_certificate_store:
path: C:\temp\cert.pfx
state: present
password: VeryStrongPasswordHere!
become: yes
become_method: runas
- name: import pfx certificate without password and set private key as un-exportable
win_certificate_store:
path: C:\temp\cert.pfx
state: present
key_exportable: no
# usually you don't set this here but it is for illustrative purposes
vars:
ansible_winrm_transport: credssp
- name: remove a certificate based on file thumbprint
win_certificate_store:
path: C:\temp\cert.pem
state: absent
- name: remove a certificate based on thumbprint
win_certificate_store:
thumbprint: BD7AF104CF1872BDB518D95C9534EA941665FD27
state: absent
- name: remove certificate based on thumbprint is CurrentUser/TrustedPublishers store
win_certificate_store:
thumbprint: BD7AF104CF1872BDB518D95C9534EA941665FD27
state: absent
store_location: CurrentUser
store_name: TrustedPublisher
- name: export certificate as der encoded file
win_certificate_store:
path: C:\temp\cert.cer
state: exported
file_type: der
- name: export certificate and key as pfx encoded file
win_certificate_store:
path: C:\temp\cert.pfx
state: exported
file_type: pkcs12
password: AnotherStrongPass!
become: yes
become_method: runas
become_user: SYSTEM
'''
RETURN = r'''
thumbprints:
description: A list of certificate thumbprints that were touched by the
module.
returned: success
type: list
sample: ["BC05633694E675449136679A658281F17A191087"]
'''

@ -0,0 +1,4 @@
win_cert_dir: '{{win_output_dir}}\win_certificate'
key_password: password
subj_thumbprint: 'BD7AF104CF1872BDB518D95C9534EA941665FD27'
root_thumbprint: 'BC05633694E675449136679A658281F17A191087'

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDKDCCAhCgAwIBAgIJAP1vIdGgMJv/MA0GCSqGSIb3DQEBCwUAMCgxGTAXBgNV
BAMMEHJvb3QuYW5zaWJsZS5jb20xCzAJBgNVBAYTAlVTMCAXDTE3MTIxNTA4Mzkz
MloYDzIwODYwMTAyMDgzOTMyWjAoMRkwFwYDVQQDDBByb290LmFuc2libGUuY29t
MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmq
YT8eZY6rFQKnmScUGnnUH1tLQ+3WQpfKiWygCUSb1CNqO3J1u3pGMEqYM58LK4Kr
Mpskv7K1tCV/EMZqGTqXAIfSLy9umlb/9C3AhL9thBPn5I9dam/EmrIZktI9/w5Y
wBXn4toe+OopA3QkMQh9BUjUCPb9fdOI+ir7OGFZMmxXmiM64+BEeywM2oSGsdZ9
5hU378UBu2IX4+OAV8Fbr2l6VW+Fxg/tKIOo6Bs46Pa4EZgtemOqs3kxYBOltBTb
vFcLsLa4KYVu5Ge5YfB0Axfaem7PoP8IlMs8gxyojZ/r0o5hzxUcYlL/h8GeeoLW
PFFdiAS+UgxWINOqNXMCAwEAAaNTMFEwHQYDVR0OBBYEFLp9k4LmOnAR4ROrqhb+
CFdbk2+oMB8GA1UdIwQYMBaAFLp9k4LmOnAR4ROrqhb+CFdbk2+oMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGksycHsjGbXfWfuhQh+CvXk/A2v
MoNgiHtNMTGliVNgoVp1B1rj4x9xyZ8YrO8GAmv8jaCwCShd0B5Ul4aZVk1wglVv
lFAwb4IAZN9jv9+fw5BRzQ2tLhkVWIEwx6pZkhGhhjBvMaplLN5JwBtsdZorFbm7
wuKiUKcFAM28acoOhCmOhgyNNBZpZn5wXaQDY43AthJOhitAV7vph4MPUkwIJnOh
MA5GJXEqS58TE9z9pkhQnn9598G8tmOXyA2erAoM9JAXM3EYHxVpoHBb9QRj6WAw
XVBo6qRXkwjNEM5CbnD4hVIBsdkOGsDrgd4Q5izQZ3x+jFNkdL/zPsXjJFw=
-----END CERTIFICATE-----

@ -0,0 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyaphPx5ljqsVAqeZJxQaedQfW0tD7dZCl8qJbKAJRJvUI2o7
cnW7ekYwSpgznwsrgqsymyS/srW0JX8QxmoZOpcAh9IvL26aVv/0LcCEv22EE+fk
j11qb8SashmS0j3/DljAFefi2h746ikDdCQxCH0FSNQI9v1904j6Kvs4YVkybFea
Izrj4ER7LAzahIax1n3mFTfvxQG7Yhfj44BXwVuvaXpVb4XGD+0og6joGzjo9rgR
mC16Y6qzeTFgE6W0FNu8VwuwtrgphW7kZ7lh8HQDF9p6bs+g/wiUyzyDHKiNn+vS
jmHPFRxiUv+HwZ56gtY8UV2IBL5SDFYg06o1cwIDAQABAoIBAFRpZNsutgPJyLmb
vZeF6q8kAxwLnRtom+c9d9hoBHkbYOiSBuAaN6cuyffvTWw9GLFRR5V5BGSheg5X
6YWj03uayTYQ3H9WJHRWHrcn5mjaRnaukhUQXQT7nmT+H16xZJl0vLJupZ33aOla
0X9DxuJusk+RsU7xPEHXDCABl8/m7v3cFttUBughGBG5oDuzKlFbhXPwA8/yeJ1v
qdXKxENi9HO4X5fH1l0vFNIhEqvUVKjw/AzapYtr+bv1wssoNAzvhT7CFa2GjPQ0
Ibcq3+RxyAN4iQVITy86Yl4LW1jLx63wbg9q1WG/ca9K/OEAuT7ebJNeMYmM+kf7
sf6A8wECgYEA+nnLJ4QtANtAs6nmDC106DTx1cOf3Yq9JOAvmGLomF/8SrUzZbXM
F+JcZcttXuuFIFcZD0K7fFP9sx2ITH//BS5V0B0x7Z2olWexVjR6/5pOVFPu19ow
tyDCNi5BlTPbvSr/fAxjmO9SgVTb8oG66i4mi0Xn5bp1E441KdvNsHECgYEAzhz/
+SjFJlJcGNvMmgfAbfv6McUv7TKrPIvVkA++Gi5QdqJjkuzL1uTfgWIY/9iDByMd
W36rFTkYrw6LTMF2dkMjul72Kkco3UExSzOmF4lFmCt3DZW6a6CExKpwk4kF2RnX
GRD0FoZZown3RbPHi9rsWxjyVy/yKGwnvXYndiMCgYEA6rnIUDfllK/jansFQtQ2
goVbPGAfKJYjurL852mJX4JUBA7bI63CnX9b52lEDXfZQf1dVpfK6zAqx/gdCtPI
QSqy8FzrtSnSGnEaFxcHTRFl5lDhuxaWIIdqeSvP+eqnOhdZZP6XN3LPdrP3isNY
Tq0BIfNY5khd/v19hMSfdYECgYBQ8h6tMY/LrwiwUpIV4/l0uELYDQL3erC5RImI
3EXiblH3ZWsJpqmfKZ+FZos+3z8GLIo5BpQV76h8B5A5grkNVOzRIr42eF/aFOJR
EGWoVKbaTiehVC40WoQJ4I35wxRi4L0TAQ97USQe3akY3LP/fujYFgIGr7PAoEkz
JRX2VQKBgQDir8/a3FZVo6nYI8zIhBz8xqZJIgvlYQqiQFFwADu5eNPMvNIaVy+6
7HKibGM2jPkuS2KHdc8WUp8IrRRMui04qE7kRxVu41QXEBfPiDvrvAQf8SfJe631
XvYeZr7HKY4NI5J0ENcb54d7DLQ8a1/wL/GeLVrfUWG35Ra5MW57Og==
-----END RSA PRIVATE KEY-----

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIC0TCCAbkCCQC/MtOBa1UDpzANBgkqhkiG9w0BAQsFADAoMRkwFwYDVQQDDBBy
b290LmFuc2libGUuY29tMQswCQYDVQQGEwJVUzAgFw0xNzEyMTUwODU2MzBaGA8y
MDg2MDEwMjA4NTYzMFowKzEcMBoGA1UEAwwTc3ViamVjdC5hbnNpYmxlLmNvbTEL
MAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDszqdF
So3GlVP1xUnN4bSPrFRFiOl/Mqup0Zn5UJJUR9wLnRD+OLcq7kKin6hYqozSu7cC
+BnWQoq7vGSSNVqv7BqFMwzGJt9IBUQv0UqIQkA/duUdKdAiMn2PQRsNDnkWEbTj
4xsitItVNv84cDG0lkZBYyTgfyZlZLZWplkpUQkrZhoFCekZRJ+ODrqNW3W560rr
OUIh+HiQeBqocat6OdxgICBqpUh8EVo1iha3DXjGN08q5utg6gmbIl2VBaVJjfyd
wnUSqHylJwh6WCIEh+HXsn4ndfNWSN/fDqvi5I10V1j6Zos7yqQf8qAezUAm6eSq
hLgZz0odq9DsO4HHAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFK5mVIJ2D+kI0kk
sxnW4ibWFjzlYFYPYrZg+2JFIVTbKBg1YzyhuIKm0uztqRxQq5iLn/C/uponHoqF
7KDQI37KAJIQdgSva+mEuO9bZAXg/eegail2hN6np7HjOKlPu23s40dAbFrbcOWP
VbsBEPDP0HLv6OgbQWzNlE9HO1b7pX6ozk3q4ULO7IR85P6OHYsBBThL+qsOTzg/
gVknuB9+n9hgNqZcAcXBLDetOM9aEmYJCGk0enYP5UGLYpseE+rTXFbRuHTPr1o6
e8BetiSWS/wcrV4ZF5qr9NiYt5eD6JzTB5Rn5awxxj0FwMtrBu003lLQUWxsuTzz
35/RLY4=
-----END CERTIFICATE-----

@ -0,0 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA7M6nRUqNxpVT9cVJzeG0j6xURYjpfzKrqdGZ+VCSVEfcC50Q
/ji3Ku5Cop+oWKqM0ru3AvgZ1kKKu7xkkjVar+wahTMMxibfSAVEL9FKiEJAP3bl
HSnQIjJ9j0EbDQ55FhG04+MbIrSLVTb/OHAxtJZGQWMk4H8mZWS2VqZZKVEJK2Ya
BQnpGUSfjg66jVt1uetK6zlCIfh4kHgaqHGrejncYCAgaqVIfBFaNYoWtw14xjdP
KubrYOoJmyJdlQWlSY38ncJ1Eqh8pScIelgiBIfh17J+J3XzVkjf3w6r4uSNdFdY
+maLO8qkH/KgHs1AJunkqoS4Gc9KHavQ7DuBxwIDAQABAoIBAQDfjqBfS+jYZrUi
uqPYV5IMaNYN5xj4Wi+xXA0OT0A1jLlxxU/7kDNrtg72U9+sBSZ483nstag+nAc5
ALu5Q+FfX3gR84XFs4DrDv22XtEMHe9leqsFgynYfu4GRaJyCw3JBeJNmWNOuj8n
rYn4EAL8xzmAFUcFIURwSEnTN6vI0cS09nQukz+9CIBuGr7TPMET8YlATDJcH+Ua
EGZ9MAFXdKF6adC2nrCVBDNr8mUEpK1XdQcPH2bvcTuZ3Jj5AF2rOrcHq4FZUm97
8PaMH6Sarxhwl+ycwrKbU5aEzUYTk67k0V6m9lyvH9z3O3Y84Tr3cZZ5WxdnG6Ri
72MFlfgRAoGBAP8wA+KWJ/ttmEXAoSX4J2fPl7X1RhR+1zPNdLY7iX0uNstL8IFH
vUN9JHi1Tr7llav+2bUTOu2EMDVmDWZH0s/qKOn+GmqIQLp0441fVAiamTcgwGKE
Wwsu4dg10IJ9akHIIbrILT0CvRcIRf67EYLBj3ZwfR+wF1ncefbsxWA9AoGBAO2P
qGMn+yrIi5DZF23x6iD2Y7bIdlUmqIqwb99XhW+3YJmRuh1EuN6XP2bIveRa9xvm
Q7bbcQM0Yv2c7eTyxpzz2I4bmnccVbs6M1VhtkyQEy5+X5yOl9wnitaaUrbWFy/w
kDPuISjLl3xDlxd6dbjf70fkG5oogx5c5toEyWZTAoGAK1CHGErMdozfr9dGgx9f
8Or3oVcEki4FcTGKgfQRHkJd4pv9MrRul6oCKsr7lsN5aDxVz7p34iDx3d54n8fJ
LKleUHllGngOJJf6l+B6bwtuvkC85vv4SCmpA/3+amfHRWsm7oFTzGtOlT4+Q0KV
clBQfZYSZvKIxCP8P8ForzECgYEAjDOad1qjOy68X7Ifx71cJjQDyV4pqDt2gNN8
Ut1+XN5m3ntI0fk6+fNdcbXLjDe7WvXcxNBhtDh4q6CwLcyyNvMavVPBJ8bLOgIx
RZSzWCA3kdr3ZpgpO78Ci4DsjAdyC9L36A4D9+Wf87CYPT0CuSdAOrd/Ks36BDNj
8wucKQ0CgYAaRwQ18nkemrpQ/+EQgEWnWfqgB+6T4ygZ4ZTym0FAtG7CdLxvCi8V
toyn+zi+yFTRFXHDmvg9HLIIMK/hRQjgc8Ns5nDwgQlGwCZTvjVbD4anCr1IWuky
owvxKWsHseNilKrnAk2maQxrrrpSk8QWrp2CFw04LsWGTxtFvstBmg==
-----END RSA PRIVATE KEY-----

@ -0,0 +1,121 @@
### keys in files/ have been generated with
# generate root private key
# openssl genrsa -aes256 -out enckey.pem 2048
# openssl rsa -in envkey.pem -out root-key.pem
#
# generate root certificate
# openssl req -x509 -key root-key.pem -days 24855 -out root-vert.pem -subj "/CN=root.ansible.com/C=US"
#
# generate subject private key
# openssl genrsa -aes256 -out enckey.pem 2048
# openssl rsa -in enckey.pem -out subj-key.pem
#
# generate subject certificate
# openssl req -new -key subj-key.pem -out cert.csr -subj "/CN=subject.ansible.com/C=US"
# openssl x509 -req -in cert.csr -CA root-cert.pem -CAkey root-key.pem -CAcreateserial -out subj-cert.pem -days 24855
###
---
- name: ensure test dir is present
win_file:
path: '{{win_cert_dir}}\exported'
state: directory
- name: ensure certificates are removed from store before test
win_certificate_store:
thumbprint: '{{item}}'
state: absent
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
- name: ensure certificates are removed from custom store before test
win_certificate_store:
thumbprint: '{{item}}'
state: absent
store_name: TrustedPeople
store_location: CurrentUser
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
# these files are created on the fly so we don't store binary in the git repo
- name: create PKCS12 without password
command: 'openssl pkcs12 -export -out subj-cert-without-pass.pfx -inkey subj-key.pem -in subj-cert.pem -passout pass:'
args:
chdir: '{{role_path}}/files'
delegate_to: localhost
run_once: yes
- name: create PKCS12 with password
command: 'openssl pkcs12 -export -out subj-cert-with-pass.pfx -inkey subj-key.pem -in subj-cert.pem -passout pass:{{key_password}}'
args:
chdir: '{{role_path}}/files'
delegate_to: localhost
run_once: yes
- name: create DER encoded cert
command: openssl x509 -outform der -in subj-cert.pem -out subj-cert.cer
args:
chdir: '{{role_path}}/files'
delegate_to: localhost
run_once: yes
- name: create PEM encoded PKCS7 file
command: openssl crl2pkcs7 -nocrl -certfile subj-cert.pem -certfile root-cert.pem -out chain.pem
args:
chdir: '{{role_path}}/files'
delegate_to: localhost
run_once: yes
- name: create DER encoded PKCS7 file
command: openssl crl2pkcs7 -nocrl -certfile subj-cert.pem -certfile root-cert.pem -out chain.p7b -outform der
args:
chdir: '{{role_path}}/files'
delegate_to: localhost
run_once: yes
- name: copy across test cert files
win_copy:
src: files/
dest: '{{win_cert_dir}}'
- block:
- name: run tests
include_tasks: test.yml
always:
- name: ensure generated keys are deleted
file:
path: '{{role_path}}/files/{{item}}'
state: absent
delegate_to: localhost
run_once: yes
with_items:
- subj-cert-with-pass.pfx
- subj-cert-without-pass.pfx
- subj-cert.cer
- chain.pem
- chain.p7b
- name: ensure certificates are removed from store after test
win_certificate_store:
thumbprint: '{{item}}'
state: absent
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
- name: ensure certificates are removed from custom store after test
win_certificate_store:
thumbprint: '{{item}}'
state: absent
store_name: TrustedPeople
store_location: CurrentUser
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
- name: ensure test dir is deleted
win_file:
path: '{{win_cert_dir}}'
state: absent

@ -0,0 +1,801 @@
---
- name: fail with invalid store location
win_certificate_store:
state: present
path: '{{win_cert_dir}}\subj-cert.pem'
store_location: FakeLocation
register: fail_fake_location
failed_when: "fail_fake_location.msg != 'Get-AnsibleParam: Argument store_location needs to be one of CurrentUser,LocalMachine but was FakeLocation.'"
- name: fail with invalid store name
win_certificate_store:
state: present
path: '{{win_cert_dir}}\subj-cert.pem'
store_name: FakeName
register: fail_fake_name
failed_when: "fail_fake_name.msg != 'Get-AnsibleParam: Argument store_name needs to be one of AddressBook,AuthRoot,CertificateAuthority,Disallowed,My,Root,TrustedPeople,TrustedPublisher but was FakeName.'"
- name: fail when state=present and no path is set
win_certificate_store:
state: present
register: fail_present_no_path
failed_when: "fail_present_no_path.msg != 'Get-AnsibleParam: Missing required argument: path'"
- name: fail when state=exported and no path is set
win_certificate_store:
state: exported
thumbprint: ABC
register: fail_export_no_path
failed_when: "fail_export_no_path.msg != 'Get-AnsibleParam: Missing required argument: path'"
- name: fail when state=exported and no thumbprint is set
win_certificate_store:
state: exported
path: '{{win_cert_dir}}'
register: fail_export_no_thumbprint
failed_when: "fail_export_no_thumbprint.msg != 'Get-AnsibleParam: Missing required argument: thumbprint'"
- name: fail to export thumbprint when path is a dir
win_certificate_store:
state: exported
thumbprint: '{{subj_thumbprint}}'
path: '{{win_cert_dir}}'
register: fail_export_path_is_dir
failed_when: fail_export_path_is_dir.msg != "Cannot export cert to path '" + win_cert_dir + "' as it is a directory"
- name: fail when state=absent and not path or thumbprint is set
win_certificate_store:
state: absent
register: fail_absent_no_path_or_thumbprint
failed_when: fail_absent_no_path_or_thumbprint.msg != 'Either path or thumbprint must be set when state=absent'
- name: import pem certificate (check)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.pem'
state: present
register: import_pem_check
check_mode: yes
- name: get result of import pem certificate (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pem_result_check
- name: assert results of import pem certificate (check)
assert:
that:
- import_pem_check is changed
- import_pem_check.thumbprints == [subj_thumbprint]
- import_pem_result_check.stdout_lines[0] == "False"
- name: import pem certificate
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.pem'
state: present
register: import_pem
- name: get result of import pem certificate
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pem_result
- name: assert results of import pem certificate
assert:
that:
- import_pem is changed
- import_pem.thumbprints == [subj_thumbprint]
- import_pem_result.stdout_lines[0] == "True"
- name: import pem certificate (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.pem'
state: present
register: import_pem_again
- name: assert results of import pem certificate (idempotent)
assert:
that:
- not import_pem_again is changed
- name: remove certificate based on thumbprint (check)
win_certificate_store:
thumbprint: '{{subj_thumbprint}}'
state: absent
register: remove_thumbprint_check
check_mode: yes
- name: get result of remove certificate based on thumbprint (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: remove_thumbprint_result_check
- name: assert results of remove certificate based on thumbprint (check)
assert:
that:
- remove_thumbprint_check is changed
- remove_thumbprint_check.thumbprints == [subj_thumbprint]
- remove_thumbprint_result_check.stdout_lines[0] == "True"
- name: remove certificate based on thumbprint
win_certificate_store:
thumbprint: '{{subj_thumbprint}}'
state: absent
register: remove_thumbprint
- name: get result of remove certificate based on thumbprint
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: remove_thumbprint_result
- name: assert results of remove certificate based on thumbprint
assert:
that:
- remove_thumbprint is changed
- remove_thumbprint.thumbprints == [subj_thumbprint]
- remove_thumbprint_result.stdout_lines[0] == "False"
- name: remove certificate based on thumbprint (idempotent)
win_certificate_store:
thumbprint: '{{subj_thumbprint}}'
state: absent
register: remove_thumbprint_again
- name: assert results of remove certificate based on thumbprint (idempotent)
assert:
that:
- not remove_thumbprint_again is changed
- name: import der certificate (check)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: present
register: import_der_check
check_mode: yes
- name: get result of import der certificate (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_der_result_check
- name: assert results of import der certificate (check)
assert:
that:
- import_der_check is changed
- import_der_check.thumbprints == [subj_thumbprint]
- import_der_result_check.stdout_lines[0] == "False"
- name: import der certificate
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: present
register: import_der
- name: get result of import der certificate
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_der_result
- name: assert results of import der certificate
assert:
that:
- import_der is changed
- import_der.thumbprints == [subj_thumbprint]
- import_der_result.stdout_lines[0] == "True"
- name: import der certificate (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: present
register: import_der_again
- name: assert results of import der certificate (idempotent)
assert:
that:
- not import_der_again is changed
- name: remove certificate based on path (check)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: absent
register: remove_path_check
check_mode: yes
- name: get result of remove certificate based on path (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: remove_path_result_check
- name: assert results of remove certificate based on path (check)
assert:
that:
- remove_path_check is changed
- remove_path_check.thumbprints == [subj_thumbprint]
- remove_path_result_check.stdout_lines[0] == "True"
- name: remove certificate based on path
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: absent
register: remove_path
- name: get result of remove certificate based on path
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: remove_path_result
- name: assert results of remove certificate based on path
assert:
that:
- remove_path is changed
- remove_path.thumbprints == [subj_thumbprint]
- remove_path_result.stdout_lines[0] == "False"
- name: remove certificate based on path (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert.cer'
state: absent
register: remove_path_again
- name: assert results of remove certificate based on path (idempotent)
assert:
that:
- not remove_path_again is changed
- name: import PEM encoded p7b chain (check)
win_certificate_store:
path: '{{win_cert_dir}}\chain.pem'
state: present
register: import_pem_p7b_check
check_mode: yes
- name: get result of subj in p7b chain (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pem_p7b_subj_result_check
- name: get result of root in p7b chain (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{root_thumbprint}}" }) { $true } else { $false }
register: import_pem_p7b_root_result_check
- name: assert results of import PEM encoded p7b chain (check)
assert:
that:
- import_pem_p7b_check is changed
- import_pem_p7b_check.thumbprints|count == 2
- subj_thumbprint in import_pem_p7b_check.thumbprints
- root_thumbprint in import_pem_p7b_check.thumbprints
- import_pem_p7b_subj_result_check.stdout_lines[0] == "False"
- import_pem_p7b_root_result_check.stdout_lines[0] == "False"
- name: import PEM encoded p7b chain
win_certificate_store:
path: '{{win_cert_dir}}\chain.pem'
state: present
register: import_pem_p7b
- name: get result of subj in p7b chain
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pem_p7b_subj_result
- name: get result of root in p7b chain
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{root_thumbprint}}" }) { $true } else { $false }
register: import_pem_p7b_root_result
- name: assert results of import PEM encoded p7b chain
assert:
that:
- import_pem_p7b is changed
- import_pem_p7b.thumbprints|count == 2
- subj_thumbprint in import_pem_p7b.thumbprints
- root_thumbprint in import_pem_p7b.thumbprints
- import_pem_p7b_subj_result.stdout_lines[0] == "True"
- import_pem_p7b_root_result.stdout_lines[0] == "True"
- name: import PEM encoded p7b chain (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\chain.pem'
state: present
register: import_pem_p7b_again
- name: assert results of import PEM encoded p7b chain (idempotent)
assert:
that:
- not import_pem_p7b_again is changed
- name: remove p7b chain certs
win_certificate_store:
thumbprint: '{{item}}'
state: absent
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
- name: import DER encoded p7b chain into custom store (check)
win_certificate_store:
path: '{{win_cert_dir}}\chain.p7b'
state: present
store_name: TrustedPeople
store_location: CurrentUser
register: import_der_p7b_check
check_mode: yes
- name: get result of subj in p7b chain in custom store (check)
win_shell: if (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_der_p7b_subj_result_check
- name: get result of root in p7b chain in custom store (check)
win_shell: if (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{root_thumbprint}}" }) { $true } else { $false }
register: import_der_p7b_root_result_check
- name: assert results of import DER encoded p7b chain into custom store (check)
assert:
that:
- import_der_p7b_check is changed
- import_der_p7b_check.thumbprints|count == 2
- subj_thumbprint in import_der_p7b_check.thumbprints
- root_thumbprint in import_der_p7b_check.thumbprints
- import_der_p7b_subj_result_check.stdout_lines[0] == "False"
- import_der_p7b_root_result_check.stdout_lines[0] == "False"
- name: import DER encoded p7b chain into custom store
win_certificate_store:
path: '{{win_cert_dir}}\chain.p7b'
state: present
store_name: TrustedPeople
store_location: CurrentUser
register: import_der_p7b
- name: get result of subj in p7b chain in custom store
win_shell: if (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_der_p7b_subj_result
- name: get result of root in p7b chain in custom store
win_shell: if (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{root_thumbprint}}" }) { $true } else { $false }
register: import_der_p7b_root_result
- name: assert results of import DER encoded p7b chain into custom store
assert:
that:
- import_der_p7b is changed
- import_der_p7b.thumbprints|count == 2
- subj_thumbprint in import_der_p7b.thumbprints
- root_thumbprint in import_der_p7b.thumbprints
- import_der_p7b_root_result.stdout_lines[0] == "True"
- import_der_p7b_root_result.stdout_lines[0] == "True"
- name: import DER encoded p7b chain into custom store (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\chain.p7b'
state: present
store_name: TrustedPeople
store_location: CurrentUser
register: import_der_p7b_again
- name: assert results of import DER encoded p7b chain into custom store (idempotent)
assert:
that:
- not import_der_p7b_again is changed
- name: remove p7b chain certs from custom store
win_certificate_store:
thumbprint: '{{item}}'
state: absent
store_name: TrustedPeople
store_location: CurrentUser
with_items:
- '{{subj_thumbprint}}'
- '{{root_thumbprint}}'
- name: import pfx without password and non exportable (check)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-without-pass.pfx'
state: present
key_exportable: no
vars: &become_vars
ansible_become: yes
ansible_become_method: runas
ansible_become_user: '{{ansible_user}}'
ansible_become_pass: '{{ansible_password}}'
register: import_pfx_without_pass_check
check_mode: yes
- name: get results of import pfx without password and non exportable (check)
win_shell: if (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pfx_without_pass_result_check
- name: assert results of import pfx without password and non exportable (check)
assert:
that:
- import_pfx_without_pass_check is changed
- import_pfx_without_pass_check.thumbprints == [subj_thumbprint]
- import_pfx_without_pass_result_check.stdout_lines[0] == "False"
- name: import pfx without password and non exportable
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-without-pass.pfx'
state: present
key_exportable: no
vars: *become_vars
register: import_pfx_without_pass
- name: get results of import pfx without password and non exportable
win_shell: (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }).PrivateKey.CspKeyContainerInfo.Exportable
vars: *become_vars
register: import_pfx_without_pass_result
- name: assert results of import pfx without password and non exportable
assert:
that:
- import_pfx_without_pass is changed
- import_pfx_without_pass.thumbprints == [subj_thumbprint]
- import_pfx_without_pass_result.stdout_lines[0] == "False"
- name: import pfx without password and non exportable (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-without-pass.pfx'
state: present
key_exportable: no
vars: *become_vars
register: import_pfx_without_pass_again
- name: assert results of import pfx without password and non exportable (idempotent)
assert:
that:
- not import_pfx_without_pass_again is changed
- name: fail import pfx with password and none set
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-with-pass.pfx'
state: present
store_location: CurrentUser
store_name: TrustedPeople
register: fail_import_pfx_with_password
failed_when: "'Failed to load cert from file' not in fail_import_pfx_with_password.msg and 'The specified network password is not correct' not in fail_import_pfx_with_password.msg"
- name: import pfx with password (check)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-with-pass.pfx'
state: present
password: '{{key_password}}'
store_location: CurrentUser
store_name: TrustedPeople
register: import_pfx_with_pass_check
vars: *become_vars
check_mode: yes
- name: get results of import pfx with password (check)
win_shell: if (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }) { $true } else { $false }
register: import_pfx_with_pass_result_check
- name: assert results of import pfx with password (check)
assert:
that:
- import_pfx_with_pass_check is changed
- import_pfx_with_pass_check.thumbprints == [subj_thumbprint]
- import_pfx_with_pass_result_check.stdout_lines[0] == "False"
- name: import pfx with password
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-with-pass.pfx'
state: present
password: '{{key_password}}'
store_location: CurrentUser
store_name: TrustedPeople
vars: *become_vars
register: import_pfx_with_pass
- name: get results of import pfx with password
win_shell: (Get-ChildItem -Path Cert:\CurrentUser\TrustedPeople | Where-Object { $_.Thumbprint -eq "{{subj_thumbprint}}" }).PrivateKey.CspKeyContainerInfo.Exportable
vars: *become_vars
register: import_pfx_with_pass_result
- name: assert results of import pfx with password
assert:
that:
- import_pfx_with_pass is changed
- import_pfx_with_pass.thumbprints == [subj_thumbprint]
- import_pfx_with_pass_result.stdout_lines[0] == "True"
- name: import pfx with password (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\subj-cert-with-pass.pfx'
state: present
password: '{{key_password}}'
store_location: CurrentUser
store_name: TrustedPeople
vars: *become_vars
register: import_pfx_with_pass_again
- name: assert results of import pfx with password (idempotent)
assert:
that:
- not import_pfx_with_pass_again is changed
- name: import root cert for export tests
win_certificate_store:
path: '{{win_cert_dir}}\root-cert.pem'
state: present
- name: export cert as pem (check)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.pem'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pem
register: export_pem_check
check_mode: yes
- name: get result of export cert as pem (check)
win_stat:
path: '{{win_cert_dir}}\exported\cert.pem'
register: export_pem_result_check
- name: assert results of export cert as pem (check)
assert:
that:
- export_pem_check is changed
- export_pem_check.thumbprints == [subj_thumbprint]
- export_pem_result_check.stat.exists == False
- name: export cert as pem
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.pem'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pem
register: export_pem
- name: get result of export cert as pem
win_stat:
path: '{{win_cert_dir}}\exported\cert.pem'
register: export_pem_result
- name: assert results of export cert as pem
assert:
that:
- export_pem is changed
- export_pem.thumbprints == [subj_thumbprint]
- export_pem_result.stat.checksum == '1ebf5467d18230e9f611940a74d12f1d0bc819b7'
- name: export cert as pem (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.pem'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pem
register: export_pem_again
- name: assert results of export cert as pem
assert:
that:
- not export_pem_again is changed
- name: export cert as der (check)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.cer'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: der
register: export_der_check
check_mode: yes
- name: get result of export cert as der (check)
win_stat:
path: '{{win_cert_dir}}\exported\cert.cer'
register: export_der_result_check
- name: assert results of export cert as der (check)
assert:
that:
- export_der_check is changed
- export_der_check.thumbprints == [subj_thumbprint]
- export_der_result_check.stat.exists == False
- name: export cert as der
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.cer'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: der
register: export_der
- name: get result of export cert as der
win_stat:
path: '{{win_cert_dir}}\exported\cert.cer'
register: export_der_result
- name: assert results of export cert as der
assert:
that:
- export_der is changed
- export_der.thumbprints == [subj_thumbprint]
- export_der_result.stat.checksum == 'bd7af104cf1872bdb518d95c9534ea941665fd27'
- name: export cert as der (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.cer'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: der
register: export_der_again
- name: assert results of export cert as der
assert:
that:
- not export_der_again is changed
- name: export cert as der replacing pem
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.pem'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: der
register: export_der_over_pem
- name: get result of export cert as der replacing pem
win_stat:
path: '{{win_cert_dir}}\exported\cert.pem'
register: export_der_over_pem_result
- name: assert results of export cert as der replacing pem
assert:
that:
- export_der_over_pem is changed
- export_der_over_pem.thumbprints == [subj_thumbprint]
- export_der_over_pem_result.stat.checksum == 'bd7af104cf1872bdb518d95c9534ea941665fd27'
- name: export cert as pem replacing der
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert.cer'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pem
register: export_pem_over_der
- name: get result of export cert as pem replacing der
win_stat:
path: '{{win_cert_dir}}\exported\cert.cer'
register: export_pem_over_der_result
- name: assert results of export cert as pem replacing der
assert:
that:
- export_pem_over_der is changed
- export_pem_over_der.thumbprints == [subj_thumbprint]
- export_pem_over_der_result.stat.checksum == '1ebf5467d18230e9f611940a74d12f1d0bc819b7'
- name: export cert with key and password as pfx (check)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
password: '{{key_password}}'
register: export_pfx_with_pass_check
vars: *become_vars
check_mode: yes
- name: get result of export cert with key and password as pfx (check)
win_stat:
path: '{{win_cert_dir}}\exported\cert-pass.pfx'
register: export_pfx_with_pass_result_check
- name: assert results of export cert with key and password as pfx (check)
assert:
that:
- export_pfx_with_pass_check is changed
- export_pfx_with_pass_check.thumbprints == [subj_thumbprint]
- export_pfx_with_pass_result_check.stat.exists == False
- name: export cert with key and password as pfx
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
password: '{{key_password}}'
vars: *become_vars
register: export_pfx_with_pass
- name: get result of export cert with key and password as pfx
win_shell: |
$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import("{{win_cert_dir}}\exported\cert-pass.pfx", "{{key_password}}", 0)
$cert.HasPrivateKey
vars: *become_vars
register: export_pfx_with_pass_result
- name: assert results of export cert with key and password as pfx
assert:
that:
- export_pfx_with_pass is changed
- export_pfx_with_pass.thumbprints == [subj_thumbprint]
- export_pfx_with_pass_result.stdout_lines[0] == "True"
- name: export cert with key and password as pfx (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
password: '{{key_password}}'
vars: *become_vars
register: export_pfx_with_pass_again
- name: assert results of export cert with key and password as pfx (idempotent)
assert:
that:
- not export_pfx_with_pass_again is changed
- name: export cert with key without password as pfx (check)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-without-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
vars: *become_vars
register: export_pfx_without_pass_check
check_mode: yes
- name: get result of export cert with key without password as pfx (check)
win_stat:
path: '{{win_cert_dir}}\exported\cert-without-pass.pfx'
register: export_pfx_without_pass_result_check
- name: assert results of export cert with key without password as pfx (check)
assert:
that:
- export_pfx_without_pass_check is changed
- export_pfx_without_pass_check.thumbprints == [subj_thumbprint]
- export_pfx_without_pass_result_check.stat.exists == False
- name: export cert with key without password as pfx
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-without-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
vars: *become_vars
register: export_pfx_without_pass
- name: get result of export cert with key without password as pfx
win_shell: |
$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import("{{win_cert_dir}}\exported\cert-without-pass.pfx", $null, 0)
$cert.HasPrivateKey
vars: *become_vars
register: export_pfx_without_pass_result
- name: assert results of export cert with key without password as pfx
assert:
that:
- export_pfx_without_pass is changed
- export_pfx_without_pass.thumbprints == [subj_thumbprint]
- export_pfx_without_pass_result.stdout_lines[0] == "True"
- name: export cert with key without password as pfx (idempotent)
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-without-pass.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
store_location: CurrentUser
store_name: TrustedPeople
vars: *become_vars
register: export_pfx_without_pass_again
- name: assert results of export cert with key without password as pfx (idempotent)
assert:
that:
- not export_pfx_without_pass_again is changed
- name: fail to export cert with key as pfx when not marked as exportable
win_certificate_store:
path: '{{win_cert_dir}}\exported\cert-fail.pfx'
thumbprint: '{{subj_thumbprint}}'
state: exported
file_type: pkcs12
vars: *become_vars
register: fail_export_non_exportable
failed_when: fail_export_non_exportable.msg != 'Cannot export cert with key as PKCS12 when the key is not marked as exportable or not accesible by the current user'
Loading…
Cancel
Save