Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate win_certificate_info module to ansible.windows repo from ansible.community repo #687

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions plugins/modules/win_certificate_info.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!powershell

# Copyright: (c) 2019, Micah Hunsberger
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

#AnsibleRequires -CSharpUtil Ansible.Basic

function ConvertTo-Timestamp($start_date, $end_date) {
if ($start_date -and $end_date) {
return (New-TimeSpan -Start $start_date -End $end_date).TotalSeconds
}
}

function Format-Date([DateTime]$date) {
return $date.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssK')
}

function Get-CertificateInfo ($cert) {
$epoch_date = Get-Date -Date "01/01/1970"

$cert_info = @{ extensions = @() }
$cert_info.friendly_name = $cert.FriendlyName
$cert_info.thumbprint = $cert.Thumbprint
$cert_info.subject = $cert.Subject
$cert_info.issuer = $cert.Issuer
$cert_info.valid_from = (ConvertTo-Timestamp -start_date $epoch_date -end_date $cert.NotBefore.ToUniversalTime())
$cert_info.valid_from_iso8601 = Format-Date -date $cert.NotBefore
$cert_info.valid_to = (ConvertTo-Timestamp -start_date $epoch_date -end_date $cert.NotAfter.ToUniversalTime())
$cert_info.valid_to_iso8601 = Format-Date -date $cert.NotAfter
$cert_info.serial_number = $cert.SerialNumber
$cert_info.archived = $cert.Archived
$cert_info.version = $cert.Version
$cert_info.has_private_key = $cert.HasPrivateKey
$cert_info.issued_by = $cert.GetNameInfo('SimpleName', $true)
$cert_info.issued_to = $cert.GetNameInfo('SimpleName', $false)
$cert_info.signature_algorithm = $cert.SignatureAlgorithm.FriendlyName
$cert_info.dns_names = [System.Collections.Generic.List`1[String]]@($cert_info.issued_to)
$cert_info.raw = [System.Convert]::ToBase64String($cert.GetRawCertData())
$cert_info.public_key = [System.Convert]::ToBase64String($cert.GetPublicKey())
if ($cert.Extensions.Count -gt 0) {
[array]$cert_info.extensions = foreach ($extension in $cert.Extensions) {
$extension_info = @{
critical = $extension.Critical
field = $extension.Oid.FriendlyName
value = $extension.Format($false)
}
if ($extension -is [System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension]) {
$cert_info.is_ca = $extension.CertificateAuthority
$cert_info.path_length_constraint = $extension.PathLengthConstraint
}
elseif ($extension -is [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]) {
$cert_info.intended_purposes = $extension.EnhancedKeyUsages.FriendlyName -as [string[]]
}
elseif ($extension -is [System.Security.Cryptography.X509Certificates.X509KeyUsageExtension]) {
$cert_info.key_usages = $extension.KeyUsages.ToString().Split(',').Trim() -as [string[]]
}
elseif ($extension -is [System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension]) {
$cert_info.ski = $extension.SubjectKeyIdentifier
}
elseif ($extension.Oid.value -eq '2.5.29.17') {
$sans = $extension.Format($true).Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries)
foreach ($san in $sans) {
$san_parts = $san.Split("=")
if ($san_parts.Length -ge 2 -and $san_parts[0].Trim() -eq 'DNS Name') {
$cert_info.dns_names.Add($san_parts[1].Trim())
}
}
}
$extension_info
}
}
return $cert_info
}

$store_location_values = ([System.Security.Cryptography.X509Certificates.StoreLocation]).GetEnumValues() | ForEach-Object { $_.ToString() }

$spec = @{
options = @{
thumbprint = @{ type = "str"; required = $false }
store_name = @{ type = "str"; default = "My"; }
store_location = @{ type = "str"; default = "LocalMachine"; choices = $store_location_values; }
}
supports_check_mode = $true
}

$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)

$thumbprint = $module.Params.thumbprint
$store_name = $module.Params.store_name
$store_location = [System.Security.Cryptography.X509Certificates.Storelocation]"$($module.Params.store_location)"

$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $store_name, $store_location
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)

$module.Result.exists = $false
$module.Result.certificates = @()

try {
if ($null -ne $thumbprint) {
$found_certs = $store.Certificates.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint, $thumbprint, $false)
}
else {
$found_certs = $store.Certificates
}

if ($found_certs.Count -gt 0) {
$module.Result.exists = $true
[array]$module.Result.certificates = $found_certs | ForEach-Object { Get-CertificateInfo -cert $_ } | Sort-Object -Property { $_.thumbprint }
}
}
finally {
$store.Close()
}

$module.ExitJson()
229 changes: 229 additions & 0 deletions plugins/modules/win_certificate_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2016, Ansible, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = r'''
---
module: win_certificate_info
short_description: Get information on certificates from a Windows Certificate Store
description:
- Returns information about certificates in a Windows Certificate Store.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to set the version when this module was added to the collection through the version_added key.

Suggested change
- Returns information about certificates in a Windows Certificate Store.
- Returns information about certificates in a Windows Certificate Store.
version_added: 2.6.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason you put 2.6.0 because it will be the upcoming version release, right?

Is there a place where we can follow the planned release dates if there is such

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version is in the galaxy.yml file and while sometimes it may have already been bumped it may still track the older release. I just compare it with the tagged releases and see if I need to increment it or not. In this case 2.5.0 is the latest release and the galaxy.yml has not been updated yet. A minor version bump is needed for new features so the next release will be 2.6.0.

As for a release schedule there hasn't been a hard rule of when to release. I usually aim for a release every 1-2 months but that is also dependent on whether there are changes to be made in a release.

version_added: 2.6.0
options:
thumbprint:
description:
- The thumbprint as a hex string of a certificate to find.
- When specified, filters the I(certificates) return value to a single certificate
- See the examples for how to format the thumbprint.
type: str
required: no
store_name:
description:
- The name of the store to search.
- See U(https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.storename)
for a list of built-in store names.
type: str
default: My
store_location:
description:
- The location of the store to search.
type: str
choices: [ CurrentUser, LocalMachine ]
default: LocalMachine
seealso:
- module: ansible.windows.win_certificate_store
author:
- Micah Hunsberger (@mhunsber)
'''

EXAMPLES = r'''
ronger4 marked this conversation as resolved.
Show resolved Hide resolved
- name: Obtain information about a particular certificate in the computer's personal store
ansible.windows.win_certificate_info:
thumbprint: BD7AF104CF1872BDB518D95C9534EA941665FD27
register: mycert

# thumbprint can also be lower case
- name: Obtain information about a particular certificate in the computer's personal store
ansible.windows.win_certificate_info:
thumbprint: bd7af104cf1872bdb518d95c9534ea941665fd27
register: mycert

- name: Obtain information about all certificates in the root store
ansible.windows.win_certificate_info:
store_name: Root
register: ca

# Import a pfx and then get information on the certificates
- name: Import pfx certificate that is password protected
ansible.windows.win_certificate_store:
path: C:\Temp\cert.pfx
state: present
password: VeryStrongPasswordHere!
become: true
become_method: runas
register: mycert

- name: Obtain information on each certificate that was touched
ansible.windows.win_certificate_info:
thumbprint: "{{ item }}"
register: mycert_stats
loop: "{{ mycert.thumbprints }}"
'''

RETURN = r'''
exists:
description:
- Whether any certificates were found in the store.
- When I(thumbprint) is specified, returns true only if the certificate mathing the thumbprint exists.
returned: success
type: bool
sample: true
certificates:
description:
- A list of information about certificates found in the store, sorted by thumbprint.
returned: success
type: list
elements: dict
contains:
archived:
description: Indicates that the certificate is archived.
type: bool
sample: false
dns_names:
description: Lists the registered dns names for the certificate.
type: list
elements: str
sample: [ '*.m.wikiquote.org', '*.wikipedia.org' ]
extensions:
description: The collection of the certificates extensions.
type: list
elements: dict
sample: [
{
"critical": false,
"field": "Subject Key Identifier",
"value": "88 27 17 09 a9 b6 18 60 8b ec eb ba f6 47 59 c5 52 54 a3 b7"
},
{
"critical": true,
"field": "Basic Constraints",
"value": "Subject Type=CA, Path Length Constraint=None"
},
{
"critical": false,
"field": "Authority Key Identifier",
"value": "KeyID=2b d0 69 47 94 76 09 fe f4 6b 8d 2e 40 a6 f7 47 4d 7f 08 5e"
},
{
"critical": false,
"field": "CRL Distribution Points",
"value": "[1]CRL Distribution Point: Distribution Point Name:Full Name:URL=http://crl.apple.com/root.crl"
},
{
"critical": true,
"field": "Key Usage",
"value": "Digital Signature, Certificate Signing, Off-line CRL Signing, CRL Signing (86)"
},
{
"critical": false,
"field": null,
"value": "05 00"
}
]
friendly_name:
description: The associated alias for the certificate.
type: str
sample: Microsoft Root Authority
has_private_key:
description: Indicates that the certificate contains a private key.
type: bool
sample: false
intended_purposes:
description: lists the intended applications for the certificate.
returned: enhanced key usages extension exists.
type: list
sample: [ "Server Authentication" ]
is_ca:
description: Indicates that the certificate is a certificate authority (CA) certificate.
returned: basic constraints extension exists.
type: bool
sample: true
issued_by:
description: The certificate issuer's common name.
type: str
sample: Apple Root CA
issued_to:
description: The certificate's common name.
type: str
sample: Apple Worldwide Developer Relations Certification Authority
issuer:
description: The certificate issuer's distinguished name.
type: str
sample: 'CN=Apple Root CA, OU=Apple Certification Authority, O=Apple Inc., C=US'
key_usages:
description:
- Defines how the certificate key can be used.
- If this value is not defined, the key can be used for any purpose.
returned: key usages extension exists.
type: list
elements: str
sample: [ "CrlSign", "KeyCertSign", "DigitalSignature" ]
path_length_constraint:
description:
- The number of levels allowed in a certificates path.
- If this value is 0, the certificate does not have a restriction.
returned: basic constraints extension exists
type: int
sample: 0
public_key:
description: The base64 encoded public key of the certificate.
type: str
cert_data:
description: The base64 encoded data of the entire certificate.
type: str
serial_number:
description: The serial number of the certificate represented as a hexadecimal string
type: str
sample: 01DEBCC4396DA010
signature_algorithm:
description: The algorithm used to create the certificate's signature
type: str
sample: sha1RSA
ski:
description: The certificate's subject key identifier
returned: subject key identifier extension exists.
type: str
sample: 88271709A9B618608BECEBBAF64759C55254A3B7
subject:
description: The certificate's distinguished name.
type: str
sample: 'CN=Apple Worldwide Developer Relations Certification Authority, OU=Apple Worldwide Developer Relations, O=Apple Inc., C=US'
thumbprint:
description:
- The thumbprint as a hex string of the certificate.
- The return format will always be upper case.
type: str
sample: FF6797793A3CD798DC5B2ABEF56F73EDC9F83A64
valid_from:
description: The start date of the certificate represented in seconds since epoch.
type: float
sample: 1360255727
valid_from_iso8601:
description: The start date of the certificate represented as an iso8601 formatted date.
type: str
sample: '2017-12-15T08:39:32Z'
valid_to:
description: The expiry date of the certificate represented in seconds since epoch.
type: float
sample: 1675788527
valid_to_iso8601:
description: The expiry date of the certificate represented as an iso8601 formatted date.
type: str
sample: '2086-01-02T08:39:32Z'
version:
description: The x509 format version of the certificate
type: int
sample: 3
'''
1 change: 1 addition & 0 deletions tests/integration/targets/win_certificate_info/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shippable/windows/group3
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
win_cert_dir: '{{ remote_tmp_dir }}\win_certificate .ÅÑŚÌβŁÈ [$!@^&test(;)]'
subj_thumbprint: 'BD7AF104CF1872BDB518D95C9534EA941665FD27'
root_thumbprint: 'BC05633694E675449136679A658281F17A191087'
20 changes: 20 additions & 0 deletions tests/integration/targets/win_certificate_info/files/root-cert.pem
Original file line number Diff line number Diff line change
@@ -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-----

19 changes: 19 additions & 0 deletions tests/integration/targets/win_certificate_info/files/subj-cert.pem
Original file line number Diff line number Diff line change
@@ -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-----

2 changes: 2 additions & 0 deletions tests/integration/targets/win_certificate_info/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir
Loading