├── Deploy-EnterpriseSubCa-Step1.ps1 ├── Deploy-EnterpriseSubCa-Step1_ECC.ps1 ├── Deploy-EnterpriseSubCa-Step2.ps1 ├── Deploy-StandAloneRootCa.ps1 ├── Deploy-StandAloneRootCa_ECC.ps1 ├── LICENSE ├── README.md ├── Samples ├── capolicy_RootCA.inf ├── capolicy_RootCA_ECC.inf ├── capolicy_SubCA.inf └── capolicy_SubCA_ECC.inf └── lib ├── Complete-AdcsCaDeployment.ps1 ├── Get-AdCsKspName.ps1 ├── Get-AdcsActiveCaName.ps1 ├── Get-AdcsCaSetupStatus.ps1 ├── Get-AdcsCaType.ps1 ├── Get-SanitizedFileName.ps1 ├── Get-TokenDescription.ps1 ├── Invoke-AutoEnrollmentTask.ps1 ├── New-AdcsCaDeployment.ps1 ├── Test-AdcsServiceAvailability.ps1 ├── Test-Flag.ps1 └── Test-KspAvailability.ps1 /Deploy-EnterpriseSubCa-Step1.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | $Script:BaseDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent 5 | 6 | # Loading all Libary Scripts we depend on 7 | Get-ChildItem -Path "$Script:BaseDirectory\lib" -Filter *.ps1 | ForEach-Object { 8 | . ($_.FullName) 9 | } 10 | 11 | New-AdcsCaDeployment ` 12 | -EnterpriseSubordinateCA ` 13 | -CaName "ADCS Labor Issuing CA 4" ` 14 | -DnSuffix "O=ADCS Labor" ` 15 | -CaPolFile "$($Script:BaseDirectory)\Samples\capolicy_SubCA.inf" ` 16 | -Cdp "http://pki.adcslabor.de/CertData/%3%8%9.crl","ldap:///CN=%7%8,CN=%3,CN=cdp,CN=Public Key Services,CN=Services,%6%10" ` 17 | -Aia "http://pki.adcslabor.de/CertData/%3%4.crt","ldap:///CN=%7,CN=aia,CN=Public Key Services,CN=Services,%6%11","http://ocsp.adcslabor.de/ocsp" ` 18 | -AuditFilter 126 ` 19 | -ValidityPeriodUnits 2 ` 20 | -CrlPeriodUnits 4 ` 21 | -CrlPeriod "Days" ` 22 | -CrlOverlapUnits 4 ` 23 | -CrlOverlapPeriod "Days" -------------------------------------------------------------------------------- /Deploy-EnterpriseSubCa-Step1_ECC.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | $Script:BaseDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent 5 | 6 | # Loading all Libary Scripts we depend on 7 | Get-ChildItem -Path "$Script:BaseDirectory\lib" -Filter *.ps1 | ForEach-Object { 8 | . ($_.FullName) 9 | } 10 | 11 | New-AdcsCaDeployment ` 12 | -EnterpriseSubordinateCA ` 13 | -KeyAlgorithm "ECDSA_P256" ` 14 | -CaName "ADCS Labor Issuing CA NG 1" ` 15 | -DnSuffix "O=ADCS Labor" ` 16 | -CaPolFile "$($Script:BaseDirectory)\Samples\capolicy_SubCA_ECC.inf" ` 17 | -Cdp "http://pki.adcslabor.de/CertData/%3%8%9.crl","ldap:///CN=%7%8,CN=%3,CN=cdp,CN=Public Key Services,CN=Services,%6%10" ` 18 | -Aia "http://pki.adcslabor.de/CertData/%3%4.crt","ldap:///CN=%7,CN=aia,CN=Public Key Services,CN=Services,%6%11","http://ocsp.adcslabor.de/ocsp" ` 19 | -AuditFilter 126 ` 20 | -ValidityPeriodUnits 2 ` 21 | -CrlPeriodUnits 4 ` 22 | -CrlPeriod "Days" ` 23 | -CrlOverlapUnits 4 ` 24 | -CrlOverlapPeriod "Days" -------------------------------------------------------------------------------- /Deploy-EnterpriseSubCa-Step2.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | $Script:BaseDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent 5 | 6 | # Loading all Libary Scripts we depend on 7 | Get-ChildItem -Path "$Script:BaseDirectory\lib" -Filter *.ps1 | ForEach-Object { 8 | . ($_.FullName) 9 | } 10 | 11 | Complete-AdcsCaDeployment -Certfile ".\certnew.cer" -------------------------------------------------------------------------------- /Deploy-StandAloneRootCa.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | $Script:BaseDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent 5 | 6 | # Loading all Libary Scripts we depend on 7 | Get-ChildItem -Path "$Script:BaseDirectory\lib" -Filter *.ps1 | ForEach-Object { 8 | . ($_.FullName) 9 | } 10 | 11 | New-AdcsCaDeployment ` 12 | -StandAloneRootCA ` 13 | -CaName "ADCS Labor Root CA 1" ` 14 | -CaPolFile "$($Script:BaseDirectory)\Samples\capolicy_RootCA.inf" ` 15 | -CaCertValidityPeriodUnits 16 ` 16 | -DsConfigDn "CN=Configuration,DC=Fabrikam,DC=com" ` 17 | -Cdp "http://pki.adcslabor.de/CertData/%3%8%9.crl","ldap:///CN=%7%8,CN=%3,CN=cdp,CN=Public Key Services,CN=Services,%6%10" ` 18 | -Aia "http://pki.adcslabor.de/CertData/%3%4.crt","ldap:///CN=%7,CN=aia,CN=Public Key Services,CN=Services,%6%11" ` 19 | -ValidityPeriodUnits 8 ` 20 | -CrlPeriodUnits 6 ` 21 | -CrlPeriod "Weeks" ` 22 | -CrlOverlapUnits 6 ` 23 | -CrlOverlapPeriod "Weeks" -------------------------------------------------------------------------------- /Deploy-StandAloneRootCa_ECC.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param() 3 | 4 | $Script:BaseDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent 5 | 6 | # Loading all Libary Scripts we depend on 7 | Get-ChildItem -Path "$Script:BaseDirectory\lib" -Filter *.ps1 | ForEach-Object { 8 | . ($_.FullName) 9 | } 10 | 11 | New-AdcsCaDeployment ` 12 | -StandAloneRootCA ` 13 | -CaName "ADCS Labor Root CA NG 1" ` 14 | -KeyAlgorithm "ECDSA_P256" ` 15 | -CaPolFile "$($Script:BaseDirectory)\Samples\capolicy_RootCA_ECC.inf" ` 16 | -CaCertValidityPeriodUnits 16 ` 17 | -Cdp "http://pki.adcslabor.de/CertData/%3%8%9.crl" ` 18 | -Aia "http://pki.adcslabor.de/CertData/%3%4.crt" ` 19 | -ValidityPeriodUnits 8 ` 20 | -CrlPeriodUnits 6 ` 21 | -CrlPeriod "Weeks" ` 22 | -CrlOverlapUnits 6 ` 23 | -CrlOverlapPeriod "Weeks" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Uwe Gradenegger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ADCSDeployment 2 | 3 | Scripts to easily deploy Microsoft Certification Authorities. 4 | 5 | It will comply to all requirements specified by the Common PKI Certificate Standard by default. 6 | 7 | ## Usage 8 | 9 | * `New-AdcsCaDeployment` installs the CA Role. 10 | * `Complete-AdcsCaDeployment` does all the necessary configuration, like installing the CA Certificate, populating Registry Values and the like. 11 | 12 | ## Samples 13 | 14 | See the sample files: 15 | * Deploy-StandAloneRootCa.ps1 16 | * Deploy-EnterpriseSubCa-Step1.ps1 17 | * Deploy-EnterpriseSubCa-Step2.ps1 -------------------------------------------------------------------------------- /Samples/capolicy_RootCA.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$Windows NT$" 3 | 4 | ; No [PolicyStatementExtension] necessary on the Root CA because 5 | ; "All Issuance Policies" is always implied for self-signed certificates 6 | 7 | [Extensions] 8 | 9 | ; Uncomment for Compliance to Common PKI Standard 10 | ; WARNING: Dont forget to uncomment the above [Extensions] statement as well 11 | ; Key Usage Extension marked as Critical 12 | ; Key Usage Extension will be Stripped of DigitalSignature (Only Certificate Signing, Offline CRL Signing, and CRL Signing remaining) 13 | ; See https://support.microsoft.com/en-us/kb/888180 for more information 14 | 15 | 2.5.29.15 = AwIBBg== 16 | Critical = 2.5.29.15 17 | 18 | ; Uncomment to remove specific Certificate Extensions 19 | ; Refer to https://support.microsoft.com/de-de/help/287547/object-ids-associated-with-microsoft-cryptography 20 | 21 | 1.3.6.1.4.1.311.21.1= ; szOID_CERTSRV_CA_VERSION 22 | 1.3.6.1.4.1.311.21.2= ; szOID_CERTSRV_PREVIOUS_CERT_HASH 23 | 24 | [Certsrv_Server] 25 | ; The following Settings will only have effect on CA Certificate renewals 26 | RenewalKeyLength=4096 27 | RenewalValidityPeriod=Years 28 | RenewalValidityPeriodUnits=8 29 | 30 | ; AlternateSignatureAlgorithm=0 makes the CA use PKCS#1 1.5 for Signatures 31 | ; AlternateSignatureAlgorithm=1 makes the CA use PKCS#1 2.1 for Signatures 32 | ; From a security perspective, PKCS#1 2.1 is recommended. 33 | ; However, many vendors (like Cisco) have not implemented PKCS#1 2.1, thus 34 | ; their devices cannot understand certificates from a CA that signs with 2.1 35 | ; For compatibility reasons, we will have to fall back to 1.5 in most cases 36 | ; There are working attacks on 1.5 in TLS, but none for PKI Certificates. 37 | ; So this should be OK from a Security perspective. 38 | ; If nothing is specified, 1.5 will be used. 39 | AlternateSignatureAlgorithm=0 -------------------------------------------------------------------------------- /Samples/capolicy_RootCA_ECC.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$Windows NT$" 3 | 4 | ; No [PolicyStatementExtension] necessary on the Root CA because 5 | ; "All Issuance Policies" is always implied for self-signed certificates 6 | 7 | [Extensions] 8 | 9 | ; Uncomment for Compliance to Common PKI Standard 10 | ; WARNING: Dont forget to uncomment the above [Extensions] statement as well 11 | ; Key Usage Extension marked as Critical 12 | ; Key Usage Extension will be Stripped of DigitalSignature (Only Certificate Signing, Offline CRL Signing, and CRL Signing remaining) 13 | ; See https://support.microsoft.com/en-us/kb/888180 for more information 14 | 15 | 2.5.29.15 = AwIBBg== 16 | Critical = 2.5.29.15 17 | 18 | ; Uncomment to remove specific Certificate Extensions 19 | ; Refer to https://support.microsoft.com/de-de/help/287547/object-ids-associated-with-microsoft-cryptography 20 | 21 | 1.3.6.1.4.1.311.21.1= ; szOID_CERTSRV_CA_VERSION 22 | 1.3.6.1.4.1.311.21.2= ; szOID_CERTSRV_PREVIOUS_CERT_HASH 23 | 24 | [Certsrv_Server] 25 | ; The following Settings will only have effect on CA Certificate renewals 26 | RenewalKeyLength=256 27 | RenewalValidityPeriod=Years 28 | RenewalValidityPeriodUnits=8 29 | 30 | ; AlternateSignatureAlgorithm=0 makes the CA use PKCS#1 1.5 for Signatures 31 | ; AlternateSignatureAlgorithm=1 makes the CA use PKCS#1 2.1 for Signatures 32 | ; From a security perspective, PKCS#1 2.1 is recommended. 33 | ; However, many vendors (like Cisco) have not implemented PKCS#1 2.1, thus 34 | ; their devices cannot understand certificates from a CA that signs with 2.1 35 | ; For compatibility reasons, we will have to fall back to 1.5 in most cases 36 | ; There are working attacks on 1.5 in TLS, but none for PKI Certificates. 37 | ; So this should be OK from a Security perspective. 38 | ; If nothing is specified, 1.5 will be used. 39 | AlternateSignatureAlgorithm=0 -------------------------------------------------------------------------------- /Samples/capolicy_SubCA.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$Windows NT$" 3 | 4 | ; Issuance Policies have to explicitly be specified for subordinate CAs 5 | ; Setting "AllIssuancePolicy" is not recommended as this violates RFC5280 6 | ; Instead, specific Issuance Policies should be used whenever possible 7 | ;[PolicyStatementExtension] 8 | ;Policies=AllIssuancePolicy 9 | 10 | ;[AllIssuancePolicy] 11 | ;OID=2.5.29.32.0 12 | 13 | [Extensions] 14 | 15 | ; Uncomment for Compliance to Common PKI Standard 16 | ; Key Usage Extension marked as Critical 17 | ; Key Usage Extension will be Stripped of DigitalSignature (Only Certificate Signing, Offline CRL Signing, and CRL Signing remaining) 18 | ; See https://support.microsoft.com/en-us/kb/888180 for more information 19 | 20 | 2.5.29.15 = AwIBBg== 21 | Critical = 2.5.29.15 22 | 23 | [BasicConstraintsExtension] 24 | PathLength=0 25 | Critical=TRUE 26 | 27 | ; Uncomment for Enhanced Key Usage Constraints 28 | ; Always add Private Key Archival and OCSP Signing! 29 | ;[EnhancedKeyUsageExtension] 30 | ;OID=1.3.6.1.4.1.311.21.5 ; CA Encryption Certificate 31 | ;OID=1.3.6.1.4.1.311.20.2.1 ; Certificate Request Agent 32 | ;OID=1.3.6.1.5.5.7.3.2 ; Client Authentication 33 | ;OID=1.3.6.1.5.5.7.3.3 ; Code Signing 34 | ;OID=1.3.6.1.4.1.311.10.3.12 ; Document Signing 35 | ;OID=1.3.6.1.4.1.311.10.3.4 ; Encrypting file system 36 | ;OID=1.3.6.1.4.1.311.10.3.4.1 ; File Recovery 37 | ;OID=1.3.6.1.5.5.7.3.5 ; IP Security End System 38 | ;OID=1.3.6.1.5.5.8.2.2 ; IP Security IKE Intermediate 39 | ;OID=1.3.6.1.5.5.7.3.6 ; IP Security Tunnel Endpoint 40 | ;OID=1.3.6.1.5.5.7.3.7 ; IP Security User 41 | ;OID=1.3.6.1.4.1.311.10.3.11 ; Key Recovery 42 | ;OID=1.3.6.1.5.2.3.5 ; KDC Authentication 43 | ;OID=1.3.6.1.4.1.311.10.3.1 ; Microsoft Trust List Signing 44 | ;OID=1.3.6.1.4.1.311.10.3.10 ; Qualified Subordination 45 | ;OID=1.3.6.1.4.1.311.10.3.9 ; Root List Signer 46 | ;OID=1.3.6.1.5.5.7.3.4 ; Secure E-mail 47 | ;OID=1.3.6.1.5.5.7.3.1 ; Server Authentication 48 | ;OID=1.3.6.1.4.1.311.20.2.2 ; Smart Card Logon 49 | ;OID=1.3.6.1.5.5.7.3.8 ; Time Stamping 50 | ;OID=1.3.6.1.5.5.7.3.9 ; OCSP Signing 51 | ;OID=1.3.6.1.4.1.311.54.1.2 ; Remote Desktop Authentication 52 | ;OID=1.3.6.1.4.1.311.21.5 ; Private Key Archival 53 | ;Critical=TRUE 54 | 55 | ; Uncomment and edit for Adding one or more Issuance Policies (aka CP/CPS) 56 | ;[PolicyStatementExtension] 57 | ;Policies=InternalPolicy 58 | 59 | ; Specifies the reference to the CPS Document 60 | ;[InternalPolicy] 61 | ;OID=1.3.6.1.4.1.99999.300.2.1.4.3.1 62 | ;Notice=CPS is to be found at: http://pki.adcslabor.de/CPS/index.html 63 | ;URL=http://pki.adcslabor.de/CPS/index.html 64 | 65 | [Certsrv_Server] 66 | ; The following Settings will only have effect on CA Certificate renewals 67 | RenewalKeyLength=4096 68 | 69 | ; LoadDefaultTemplates=0 will prevent the CA from instantly loading default 70 | ; Certificate Templates after CA installation 71 | LoadDefaultTemplates=0 72 | 73 | ; AlternateSignatureAlgorithm=0 makes the CA use PKCS#1 1.5 for Signatures 74 | ; AlternateSignatureAlgorithm=1 makes the CA use PKCS#1 2.1 for Signatures 75 | ; From a security perspective, PKCS#1 2.1 is recommended. 76 | ; However, many vendors (like Cisco) have not implemented PKCS#1 2.1, thus 77 | ; their devices cannot understand certificates from a CA that signs with 2.1 78 | ; For compatibility reasons, we will have to fall back to 1.5 in most cases 79 | ; There are working attacks on 1.5 in TLS, but none for PKI Certificates. 80 | ; So this should be OK from a Security perspective. 81 | ; If nothing is specified, 1.5 will be used. 82 | AlternateSignatureAlgorithm=0 83 | 84 | ; EnableKeyCounting configures the CA to increment a counter every time the CA 85 | ; signing key is used. Do not enable this setting unless you have a Hardware 86 | ; Security Module (HSM) and associated Key Storage Provider (KSP) that support 87 | ; key counting. The Microsoft Software KSP does NOT support key counting. 88 | ;EnableKeyCounting=0 -------------------------------------------------------------------------------- /Samples/capolicy_SubCA_ECC.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$Windows NT$" 3 | 4 | ; Issuance Policies have to explicitly be specified for subordinate CAs 5 | ; Setting "AllIssuancePolicy" is not recommended as this violates RFC5280 6 | ; Instead, specific Issuance Policies should be used whenever possible 7 | ;[PolicyStatementExtension] 8 | ;Policies=AllIssuancePolicy 9 | 10 | ;[AllIssuancePolicy] 11 | ;OID=2.5.29.32.0 12 | 13 | [Extensions] 14 | 15 | ; Uncomment for Compliance to Common PKI Standard 16 | ; Key Usage Extension marked as Critical 17 | ; Key Usage Extension will be Stripped of DigitalSignature (Only Certificate Signing, Offline CRL Signing, and CRL Signing remaining) 18 | ; See https://support.microsoft.com/en-us/kb/888180 for more information 19 | 20 | 2.5.29.15 = AwIBBg== 21 | Critical = 2.5.29.15 22 | 23 | [BasicConstraintsExtension] 24 | PathLength=0 25 | Critical=TRUE 26 | 27 | ; Uncomment for Enhanced Key Usage Constraints 28 | ; Always add Private Key Archival and OCSP Signing! 29 | ;[EnhancedKeyUsageExtension] 30 | ;OID=1.3.6.1.4.1.311.21.5 ; CA Encryption Certificate 31 | ;OID=1.3.6.1.4.1.311.20.2.1 ; Certificate Request Agent 32 | ;OID=1.3.6.1.5.5.7.3.2 ; Client Authentication 33 | ;OID=1.3.6.1.5.5.7.3.3 ; Code Signing 34 | ;OID=1.3.6.1.4.1.311.10.3.12 ; Document Signing 35 | ;OID=1.3.6.1.4.1.311.10.3.4 ; Encrypting file system 36 | ;OID=1.3.6.1.4.1.311.10.3.4.1 ; File Recovery 37 | ;OID=1.3.6.1.5.5.7.3.5 ; IP Security End System 38 | ;OID=1.3.6.1.5.5.8.2.2 ; IP Security IKE Intermediate 39 | ;OID=1.3.6.1.5.5.7.3.6 ; IP Security Tunnel Endpoint 40 | ;OID=1.3.6.1.5.5.7.3.7 ; IP Security User 41 | ;OID=1.3.6.1.4.1.311.10.3.11 ; Key Recovery 42 | ;OID=1.3.6.1.5.2.3.5 ; KDC Authentication 43 | ;OID=1.3.6.1.4.1.311.10.3.1 ; Microsoft Trust List Signing 44 | ;OID=1.3.6.1.4.1.311.10.3.10 ; Qualified Subordination 45 | ;OID=1.3.6.1.4.1.311.10.3.9 ; Root List Signer 46 | ;OID=1.3.6.1.5.5.7.3.4 ; Secure E-mail 47 | ;OID=1.3.6.1.5.5.7.3.1 ; Server Authentication 48 | ;OID=1.3.6.1.4.1.311.20.2.2 ; Smart Card Logon 49 | ;OID=1.3.6.1.5.5.7.3.8 ; Time Stamping 50 | ;OID=1.3.6.1.5.5.7.3.9 ; OCSP Signing 51 | ;OID=1.3.6.1.4.1.311.54.1.2 ; Remote Desktop Authentication 52 | ;OID=1.3.6.1.4.1.311.21.5 ; Private Key Archival 53 | ;Critical=TRUE 54 | 55 | ; Uncomment and edit for Adding one or more Issuance Policies (aka CP/CPS) 56 | ;[PolicyStatementExtension] 57 | ;Policies=InternalPolicy 58 | 59 | ; Specifies the reference to the CPS Document 60 | ;[InternalPolicy] 61 | ;OID=1.3.6.1.4.1.99999.300.2.1.4.3.1 62 | ;Notice=CPS is to be found at: http://pki.adcslabor.de/CPS/index.html 63 | ;URL=http://pki.adcslabor.de/CPS/index.html 64 | 65 | [Certsrv_Server] 66 | ; The following Settings will only have effect on CA Certificate renewals 67 | RenewalKeyLength=256 68 | 69 | ; LoadDefaultTemplates=0 will prevent the CA from instantly loading default 70 | ; Certificate Templates after CA installation 71 | LoadDefaultTemplates=0 72 | 73 | ; AlternateSignatureAlgorithm=0 makes the CA use PKCS#1 1.5 for Signatures 74 | ; AlternateSignatureAlgorithm=1 makes the CA use PKCS#1 2.1 for Signatures 75 | ; From a security perspective, PKCS#1 2.1 is recommended. 76 | ; However, many vendors (like Cisco) have not implemented PKCS#1 2.1, thus 77 | ; their devices cannot understand certificates from a CA that signs with 2.1 78 | ; For compatibility reasons, we will have to fall back to 1.5 in most cases 79 | ; There are working attacks on 1.5 in TLS, but none for PKI Certificates. 80 | ; So this should be OK from a Security perspective. 81 | ; If nothing is specified, 1.5 will be used. 82 | AlternateSignatureAlgorithm=0 83 | 84 | ; EnableKeyCounting configures the CA to increment a counter every time the CA 85 | ; signing key is used. Do not enable this setting unless you have a Hardware 86 | ; Security Module (HSM) and associated Key Storage Provider (KSP) that support 87 | ; key counting. The Microsoft Software KSP does NOT support key counting. 88 | ;EnableKeyCounting=0 -------------------------------------------------------------------------------- /lib/Complete-AdcsCaDeployment.ps1: -------------------------------------------------------------------------------- 1 | Function Complete-AdcsCaDeployment { 2 | 3 | [CmdletBinding(DefaultParameterSetName="StandaloneRootCA")] 4 | param( 5 | # Specific to Subordinate CAs 6 | [Parameter(Mandatory=$True)] 7 | [ValidateScript({Test-Path -Path $_})] 8 | [String] 9 | $CertFile 10 | ) 11 | 12 | begin { 13 | 14 | New-Variable -Option Constant -Name BUILD_NUMBER_WINDOWS_2012 -Value 9200 15 | New-Variable -Option Constant -Name CA_SERVICE_STOP_WAIT_SECONDS -Value 30 16 | New-Variable -Option Constant -Name CA_SERVICE_START_WAIT_SECONDS -Value 10 17 | New-Variable -Option Constant -Name DIRECTORY_CERTENROLL -Value "$($env:systemroot)\System32\CertSrv\CertEnroll" 18 | New-Variable -Option Constant -Name DEFAULT_LDAP_CDP -Value "ldap:///CN=%7%8,CN=%2,CN=CDP,CN=Public Key Services,CN=Services,%6%10" 19 | 20 | New-Variable -Option Constant -Name SETUP_SERVER_FLAG -Value 1 21 | New-Variable -Option Constant -Name SETUP_SUSPEND_FLAG -Value 4 22 | New-Variable -Option Constant -Name SETUP_REQUEST_FLAG -Value 8 23 | 24 | New-Variable -Option Constant -Name ENUM_ENTERPRISE_ROOTCA -Value 0 25 | New-Variable -Option Constant -Name ENUM_ENTERPRISE_SUBCA -Value 1 26 | New-Variable -Option Constant -Name ENUM_STANDALONE_ROOTCA -Value 3 27 | New-Variable -Option Constant -Name ENUM_STANDALONE_SUBCA -Value 4 28 | 29 | } 30 | 31 | process { 32 | 33 | # Ensuring the Script will be run on a supported Operating System 34 | If ([int32](Get-WmiObject Win32_OperatingSystem).BuildNumber -lt $BUILD_NUMBER_WINDOWS_2012) { 35 | Write-Error "Script must be run on Windows Server 2012 or newer! Aborting." 36 | return 37 | } 38 | 39 | # Ensuring the Script will be run with Elevation 40 | If (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { 41 | Write-Error "Script must be run as Administrator! Aborting." 42 | return 43 | } 44 | 45 | # Determine the current CA Setup Status 46 | $CaSetupStatus = Get-AdcsCaSetupStatus 47 | 48 | # Test if there is any CA Service installed 49 | If (-not (Test-Flag -Flags $CaSetupStatus -Flag $SETUP_SERVER_FLAG)) { 50 | Write-Error "Seems there is no CA installed that could be configured! Aborting." 51 | return 52 | } 53 | 54 | # This reads the CA Type from the Registry 55 | $CaType = Get-AdcsCaType 56 | 57 | # Steps specific for a subordinate CA 58 | If (($CaType -eq $ENUM_ENTERPRISE_SUBCA) -or ($CaType -eq $ENUM_STANDALONE_SUBCA)) { 59 | 60 | # Determine if there is a certificate request pending and install CA Certificate if so 61 | If (Test-Flag -Flags $CaSetupStatus -Flag $SETUP_REQUEST_FLAG) { 62 | 63 | # Ensure that new CA Certificate File is in place 64 | If (Test-Path $CertFile) { 65 | 66 | # Ensure Root CA Cert was downloaded from AD, (hopefully you published it there 67 | Invoke-AutoEnrollmentTask -MachineContext 68 | 69 | Start-Sleep -Second 15 70 | 71 | # Install the CA Certificate 72 | certutil -installcert $CertFile 73 | 74 | If ($LASTEXITCODE -ne 0) { 75 | Write-Error "An Error occurred while installing CA Certificate $($CertFile). Aborting!" 76 | return 77 | } 78 | } 79 | Else { 80 | Write-Error "No CA certificate found in $($CertFile). Aborting!" 81 | return 82 | } 83 | } 84 | } 85 | 86 | # Restart Certificate Services to reflect new Configuration 87 | 88 | Stop-Service -Name CertSvc 89 | 90 | # Implement a delay if not using the default Software KSP 91 | # Some HSM KSPs need some time to clean up their stuff before the Service can be started again 92 | If ((Get-AdcsKspName) -ne "Microsoft Software Key Storage Provider") { 93 | Write-Warning "Waiting $CA_SERVICE_STOP_WAIT_SECONDS Seconds for KSPs to close their Handles..." 94 | Start-Sleep -Second $CA_SERVICE_STOP_WAIT_SECONDS 95 | } 96 | 97 | Start-Service -Name CertSvc 98 | 99 | # The CertSrv.Admin Interface won't be instantly available 100 | # Thus we give it some time before tampering with it again 101 | Do { 102 | 103 | # We should not poll too often as every time the Query fails, we will 104 | # get another ugly DCOM Error Message 10016 in the System Event Log 105 | Start-Sleep -Seconds $CA_SERVICE_START_WAIT_SECONDS 106 | 107 | Write-Warning "Waiting for the ICertAdmin2 Interface to become available..." 108 | 109 | } While ((Test-AdcsServiceAvailability) -ne $True) 110 | 111 | # Delete the old default CRLs 112 | Get-ChildItem -Path $DIRECTORY_CERTENROLL "$($CaName)*.crl" | Remove-Item 113 | 114 | # Issuing a new CRL - this might fail if a non-Standard LDAP Path was configured 115 | certutil -CRL 116 | 117 | Get-CaCrlDistributionPoint | Where-Object { $_.Uri.StartsWith("ldap://") } | ForEach-Object -Process { 118 | 119 | If ($_ -notmatch $DEFAULT_LDAP_CDP) { 120 | 121 | Write-Host "Creating non-Standard LDAP CDP Object Container" 122 | 123 | # Creating the Object by Force 124 | Get-ChildItem $DIRECTORY_CERTENROLL "$($CaName)*.crl" | Foreach-Object { 125 | certutil -f -dspublish "$($_.FullName)" 126 | } 127 | 128 | # Issuing a new CRL - should work now if System already has been rebooted 129 | certutil -CRL 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /lib/Get-AdCsKspName.ps1: -------------------------------------------------------------------------------- 1 | function Get-AdcsKspName { 2 | 3 | [CmdletBinding()] 4 | param() 5 | 6 | begin { 7 | New-Variable -Name RegistryRoot -Value "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration" -Option Constant 8 | } 9 | 10 | process { 11 | 12 | 13 | Try { 14 | $Provider = (Get-ItemProperty -Path $RegistryRoot\$(Get-AdcsActiveCaName)\CSP -Name Provider -ErrorAction Stop).Provider 15 | return [String]$Provider 16 | } 17 | Catch { 18 | Write-Warning "No Certification Authority installed?" 19 | return 20 | } 21 | 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /lib/Get-AdcsActiveCaName.ps1: -------------------------------------------------------------------------------- 1 | function Get-AdcsActiveCaName { 2 | 3 | [CmdletBinding()] 4 | param() 5 | 6 | begin { 7 | New-Variable -Name RegistryRoot -Value "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration" -Option Constant 8 | } 9 | 10 | process { 11 | 12 | Try { 13 | $CaName = (Get-ItemProperty -Path $RegistryRoot -Name Active -ErrorAction Stop).Active 14 | return $CaName 15 | } 16 | Catch { 17 | Write-Warning "No Certification Authority installed?" 18 | return 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /lib/Get-AdcsCaSetupStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-AdcsCaSetupStatus { 2 | 3 | [CmdletBinding()] 4 | param() 5 | 6 | begin { 7 | New-Variable -Name RegistryRoot -Value "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration" -Option Constant 8 | } 9 | 10 | process { 11 | 12 | 13 | Try { 14 | $SetupStatus = (Get-ItemProperty -Path $RegistryRoot\$(Get-AdcsActiveCaName) -Name SetupStatus -ErrorAction Stop).SetupStatus 15 | return [Int]$SetupStatus 16 | } 17 | Catch { 18 | Write-Warning "No Certification Authority installed?" 19 | return 20 | } 21 | 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /lib/Get-AdcsCaType.ps1: -------------------------------------------------------------------------------- 1 | function Get-AdcsCaType { 2 | 3 | [CmdletBinding()] 4 | param() 5 | 6 | begin { 7 | New-Variable -Name RegistryRoot -Value "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration" -Option Constant 8 | } 9 | 10 | process { 11 | 12 | 13 | Try { 14 | $CaType = (Get-ItemProperty -Path $RegistryRoot\$(Get-AdcsActiveCaName) -Name CaType -ErrorAction Stop).CaType 15 | return [Int]$CaType 16 | } 17 | Catch { 18 | Write-Warning "No Certification Authority installed?" 19 | return 20 | } 21 | 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /lib/Get-SanitizedFileName.ps1: -------------------------------------------------------------------------------- 1 | function Get-SanitizedFileName { 2 | 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Mandatory=$true)] 6 | [string] 7 | $FileName 8 | ) 9 | 10 | $FileName = $FileName.Replace(" ","-") 11 | $FileName = $FileName.Replace(".","") 12 | 13 | return $FileName 14 | } -------------------------------------------------------------------------------- /lib/Get-TokenDescription.ps1: -------------------------------------------------------------------------------- 1 | Function Get-TokenDescription { 2 | 3 | # Replaces Tokens with a meaningful name 4 | # This is just for convenience to get a better readable Log 5 | 6 | param ( 7 | [Parameter(Mandatory=$True)] 8 | [string] 9 | $String 10 | ) 11 | 12 | # Two-Digit Numbers before one-digit numbers! 13 | $String = $($String.Replace("%10","")) 14 | $String = $($String.Replace("%11","")) 15 | 16 | $String = $($String.Replace("%1","")) 17 | $String = $($String.Replace("%2","")) 18 | $String = $($String.Replace("%3","")) 19 | $String = $($String.Replace("%4","")) 20 | $String = $($String.Replace("%6","")) 21 | $String = $($String.Replace("%7","")) 22 | $String = $($String.Replace("%8","")) 23 | $String = $($String.Replace("%9","")) 24 | 25 | return $String 26 | } -------------------------------------------------------------------------------- /lib/Invoke-AutoEnrollmentTask.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-AutoEnrollmentTask { 2 | 3 | [CmdletBinding()] 4 | param( 5 | [Alias("Machine")] 6 | [Parameter(Mandatory=$False)] 7 | [Switch] 8 | $MachineContext = $False 9 | ) 10 | 11 | begin {} 12 | 13 | process { 14 | 15 | # Ensuring we work with Elevation when messing with the Computer Certificate Store 16 | If ($MachineContext.IsPresent) { 17 | 18 | If (-not ( 19 | [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() 20 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { 21 | Write-Error -Message "This must be run with Elevation (Run as Administrator) when using the Machine Context!" 22 | return 23 | } 24 | } 25 | 26 | If ($MachineContext.IsPresent) { 27 | $TaskName = "SystemTask" 28 | $Flags = $TaskRunFlags.TASK_RUN_NO_FLAGS 29 | } 30 | Else { 31 | $TaskName = "UserTask" 32 | $Flags = $TaskRunFlags.TASK_RUN_AS_SELF # The task is run as the user who is calling the Run method (instead of "INTERACTIVE") 33 | } 34 | 35 | Try { 36 | 37 | $TaskScheduler = New-Object -ComObject("Schedule.Service") 38 | $TaskScheduler.Connect() 39 | 40 | $UserTask = $TaskScheduler.GetFolder("Microsoft\Windows\CertificateServicesClient").GetTask($TaskName) 41 | 42 | # https://docs.microsoft.com/en-us/windows/win32/taskschd/registeredtask-runex 43 | [void]($UserTask.RunEx( 44 | $null, 45 | $Flags, 46 | 0, 47 | $null 48 | )) 49 | } 50 | Catch { 51 | Write-Error -Message $PSItem.Exception.Message 52 | return 53 | } 54 | Finally { 55 | [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($UserTask)) 56 | [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($TaskScheduler)) 57 | } 58 | } 59 | 60 | end {} 61 | 62 | } -------------------------------------------------------------------------------- /lib/New-AdcsCaDeployment.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules @{ ModuleName="ServerManager"; ModuleVersion="2.0.0.0" } 2 | 3 | #TODO: Prevent usage on PowerShell Core 4 | #TODO: (Add ability to) Remove SMIME Capabilities 5 | #TODO: Tell user where the CSR file is to be found 6 | #TODO: Restart CA Service for Root CAs (Sub CAs end in stopped state anyway) 7 | function New-AdcsCaDeployment { 8 | 9 | [cmdletbinding(DefaultParameterSetName = "StandaloneRootCA")] 10 | param ( 11 | 12 | # Determines the CA Type to be installed, and the four different Parameter Sets 13 | 14 | [Parameter(ParameterSetName = "StandaloneRootCA", Mandatory=$True)] 15 | [Switch] 16 | $StandaloneRootCA, 17 | 18 | [Parameter(ParameterSetName = "EnterpriseRootCA", Mandatory=$True)] 19 | [Switch] 20 | $EnterpriseRootCA, 21 | 22 | [Parameter(ParameterSetName = "StandaloneSubordinateCA", Mandatory=$True)] 23 | [Switch] 24 | $StandaloneSubordinateCA, 25 | 26 | [Parameter(ParameterSetName = "EnterpriseSubordinateCA", Mandatory=$True)] 27 | [Switch] 28 | $EnterpriseSubordinateCA, 29 | 30 | # Specific to Root CAs 31 | 32 | [Parameter(ParameterSetName = "StandaloneRootCA", Mandatory=$False)] 33 | [Parameter(ParameterSetName = "EnterpriseRootCA", Mandatory=$False)] 34 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 35 | [String] 36 | $CaCertValidityPeriod = "Years", 37 | 38 | [Parameter(ParameterSetName = "StandaloneRootCA", Mandatory=$False)] 39 | [Parameter(ParameterSetName = "EnterpriseRootCA", Mandatory=$False)] 40 | [Int] 41 | $CaCertValidityPeriodUnits = 8, 42 | 43 | [Parameter(ParameterSetName = "StandaloneRootCA", Mandatory=$False)] 44 | [Parameter(ParameterSetName = "EnterpriseRootCA", Mandatory=$False)] 45 | [ValidateScript({$_ -in (Get-Timezone -ListAvailable).Id})] 46 | [String] 47 | $DesiredTimeZone = "W. Europe Standard Time", 48 | 49 | # Specific to Subordinate CAs 50 | 51 | [Parameter(ParameterSetName = "StandaloneSubordinateCA", Mandatory=$False)] 52 | [Parameter(ParameterSetName = "EnterpriseSubordinateCA", Mandatory=$False)] 53 | [String] 54 | $CsrFile = "$($env:SystemDrive)\csr_$($CaName.Replace(" ","_")).req", 55 | 56 | # Specific to Enterprise CAs 57 | 58 | [Parameter(ParameterSetName = "EnterpriseRootCA", Mandatory=$False)] 59 | [Parameter(ParameterSetName = "EnterpriseSubordinateCA", Mandatory=$False)] 60 | [Switch] 61 | $AllowRenewalOnBehalfOf, 62 | 63 | # Specific to Standalone CAs 64 | 65 | [Parameter(ParameterSetName = "StandaloneRootCA", Mandatory=$False)] 66 | [Parameter(ParameterSetName = "StandaloneSubordinateCA", Mandatory=$False)] 67 | [String] 68 | $DsConfigDn, 69 | 70 | # Generic Parameters that apply to all CA Types 71 | 72 | [Parameter(Mandatory=$True)] 73 | [String] 74 | $CaName, 75 | 76 | [Parameter(Mandatory=$False)] 77 | [String] 78 | $DnSuffix, 79 | 80 | [Parameter(Mandatory=$True)] 81 | [ValidateScript({Test-Path -Path $_})] 82 | [String] 83 | $CaPolFile, 84 | 85 | [Parameter(Mandatory=$False)] 86 | [String] 87 | $CaDbDir = "$($env:systemroot)\System32\CertLog", 88 | 89 | [Parameter(Mandatory=$False)] 90 | [String] 91 | $CaDbLogDir = $CaDbDir, 92 | 93 | [Parameter(Mandatory=$False)] 94 | [ValidateSet( 95 | "Microsoft Software Key Storage Provider", 96 | "Utimaco CryptoServer Key Storage Provider", 97 | "nCipher Security World Key Storage Provider", 98 | "SafeNet Key Storage Provider", 99 | "Cavium Key Storage Provider" 100 | )] 101 | [ValidateScript({Test-KspAvailability -Name $_})] 102 | [String] 103 | $KspName = "Microsoft Software Key Storage Provider", 104 | 105 | [Parameter(Mandatory=$False)] 106 | [ValidateSet( 107 | "Microsoft Software Key Storage Provider", 108 | "Utimaco CryptoServer Key Storage Provider", 109 | "nCipher Security World Key Storage Provider", 110 | "SafeNet Key Storage Provider", 111 | "Cavium Key Storage Provider" 112 | )] 113 | [ValidateScript({Test-KspAvailability -Name $_})] 114 | [String] 115 | $EncryptionCsp = "Microsoft Software Key Storage Provider", 116 | 117 | [Parameter(Mandatory=$False)] 118 | [ValidateSet("RSA","ECDSA_P256","ECDSA_P384","ECDSA_P521")] 119 | [String] 120 | $KeyAlgorithm = "RSA", 121 | 122 | [Parameter(Mandatory=$False)] 123 | [ValidateSet(1024,2048,3072,4096)] 124 | [Int] 125 | $KeyLength = 4096, 126 | 127 | [Parameter(Mandatory=$False)] 128 | [Switch] 129 | $AllowAdminInteraction, 130 | 131 | [Parameter(Mandatory=$False)] 132 | [ValidateSet("MD5","SHA1","SHA256","SHA384","SHA512")] 133 | [String] 134 | $HashAlgorithm = "SHA256", 135 | 136 | [Parameter(Mandatory=$False)] 137 | [Switch] 138 | $KeepProprietaryExtensions, # We will remove Microsoft Specific Certificate Extensions by default 139 | 140 | [Parameter(Mandatory=$False)] 141 | [Switch] 142 | $LegacyProfile, # We will conform to Common PKI Profile by default 143 | 144 | [Parameter(Mandatory=$True)] 145 | [String[]] 146 | $Cdp, 147 | 148 | [Parameter(Mandatory=$True)] 149 | [String[]] 150 | $Aia, 151 | 152 | [Parameter(Mandatory=$False)] 153 | [ValidateRange(1,999)] 154 | [Int] 155 | $CrlPeriodUnits = 7, 156 | 157 | [Parameter(Mandatory=$False)] 158 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 159 | [String] 160 | $CrlPeriod = "Days", 161 | 162 | [Parameter(Mandatory=$False)] 163 | [ValidateRange(0,999)] 164 | [String] 165 | $CrlOverlapUnits = 0, 166 | 167 | [Parameter(Mandatory=$False)] 168 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 169 | [String] 170 | $CrlOverlapPeriod = "Days", 171 | 172 | [Parameter(Mandatory=$False)] 173 | [ValidateRange(0,999)] 174 | [Int] 175 | $CrlDeltaPeriodUnits = 0, 176 | 177 | [Parameter(Mandatory=$False)] 178 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 179 | [String] 180 | $CrlDeltaPeriod = "Days", 181 | 182 | [Parameter(Mandatory=$False)] 183 | [ValidateRange(0,999)] 184 | [Int] 185 | $CrlDeltaOverlapUnits = 0, 186 | 187 | [Parameter(Mandatory=$False)] 188 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 189 | [String] 190 | $CrlDeltaOverlapPeriod = "Days", 191 | 192 | [Parameter(Mandatory=$False)] 193 | [ValidateRange(0,127)] 194 | [String] 195 | $AuditFilter = 127, 196 | 197 | [Parameter(Mandatory=$False)] 198 | [ValidateRange(0,10)] 199 | [Int] 200 | $CaPathLength, 201 | 202 | [Parameter(Mandatory=$False)] 203 | [ValidateRange(0,5)] 204 | [Int] 205 | $LogLevel = 3, 206 | 207 | [Parameter(Mandatory=$False)] 208 | [ValidateRange(0,365)] 209 | [Int] 210 | $ValidityPeriodUnits = 2, 211 | 212 | [Parameter(Mandatory=$False)] 213 | [ValidateSet("Minutes","Hours","Days","Weeks","Months","Years")] 214 | [String] 215 | $ValidityPeriod = "Years", 216 | 217 | [Parameter(Mandatory=$False)] 218 | [Switch] 219 | $NoEnforceX500NameLengths # We will not allow Subject Strings longer than 64 Characters by default, as this violates Common PKI 220 | ) 221 | 222 | begin { 223 | New-Variable -Option Constant -Name BUILD_NUMBER_WINDOWS_2016 -Value 14393 224 | 225 | New-Variable -Option Constant -Name CA_SERVICE_STOP_WAIT_SECONDS -Value 30 226 | New-Variable -Option Constant -Name CA_SERVICE_START_WAIT_SECONDS -Value 10 227 | 228 | New-Variable -Option Constant -Name DIRECTORY_CERTENROLL -Value "$($env:systemroot)\System32\CertSrv\CertEnroll" 229 | 230 | New-Variable -Option Constant -Name ENUM_ENTERPRISE_ROOTCA -Value 0 231 | New-Variable -Option Constant -Name ENUM_ENTERPRISE_SUBCA -Value 1 232 | New-Variable -Option Constant -Name ENUM_STANDALONE_ROOTCA -Value 3 233 | New-Variable -Option Constant -Name ENUM_STANDALONE_SUBCA -Value 4 234 | 235 | New-Variable -Option Constant -Name szOID_ENROLL_CERTTYPE_EXTENSION -Value "1.3.6.1.4.1.311.20.2" 236 | New-Variable -Option Constant -Name szOID_CERTSRV_CA_VERSION -Value "1.3.6.1.4.1.311.21.1" 237 | New-Variable -Option Constant -Name szOID_CERTSRV_PREVIOUS_CERT_HASH -Value "1.3.6.1.4.1.311.21.2" 238 | New-Variable -Option Constant -Name szOID_APPLICATION_CERT_POLICIES -Value "1.3.6.1.4.1.311.21.10" 239 | 240 | If ($StandaloneRootCA.IsPresent) { $CaType = $ENUM_STANDALONE_ROOTCA } 241 | If ($EnterpriseRootCA.IsPresent) { $CaType = $ENUM_ENTERPRISE_ROOTCA } 242 | If ($StandaloneSubordinateCA.IsPresent) { $CaType = $ENUM_STANDALONE_SUBCA } 243 | If ($EnterpriseSubordinateCA.IsPresent) { $CaType = $ENUM_ENTERPRISE_SUBCA } 244 | } 245 | 246 | process { 247 | 248 | # Ensuring the Script will be run on a supported Operating System 249 | If ([int](Get-WmiObject -Class Win32_OperatingSystem).BuildNumber -lt $BUILD_NUMBER_WINDOWS_2016) { 250 | Write-Error -Message "This must be run on Windows Server 2016 or newer! Aborting." 251 | Return 252 | } 253 | 254 | # Ensuring the Script will be run with Elevation 255 | If (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { 256 | Write-Error -Message "This must be run as Administrator! Aborting." 257 | Return 258 | } 259 | 260 | # Time Zone is important especially on a Standalone CA. Otherwise we mess up our issued Certificates. 261 | # For an Enterprise CA, we assume that there is working time synchronization. 262 | If (-not (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain -and (Get-TimeZone).Id -ne $DesiredTimeZone) { 263 | Write-Error "System Time Zone is not $DesiredTimeZone!" 264 | Return 265 | } 266 | 267 | # Checking if Interactive Services Detection is enabled. If not, we must reboot after setting it. 268 | If (($AllowAdminInteraction.IsPresent) -and (((Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Windows" -Name NoInteractiveServices -ErrorAction SilentlyContinue).NoInteractiveServices) -ne 0)) { 269 | 270 | # Setting the correct value for Interactive Services Detection 271 | Write-Warning -Message "Enabling Interactive Services Detection. This requires rebooting the machine before continuing." 272 | Write-Warning -Message "Run the Script again after the Reboot." 273 | 274 | [Microsoft.Win32.Registry]::SetValue( 275 | "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows", 276 | "NoInteractiveServices", 277 | 0x0, 278 | [Microsoft.Win32.RegistryValueKind]::DWORD 279 | ) 280 | 281 | Return 282 | } 283 | 284 | # Placing the capolicy.inf in the Windows Folder 285 | # We must ensure that the capolicy.inf is stored in Windows-1252 (ANSI) to reflect Umlauts and the like 286 | [void](Remove-Item -Path "$($env:systemroot)\capolicy.inf" -Force -ErrorAction SilentlyContinue) 287 | 288 | [System.IO.File]::WriteAllText( 289 | "$($env:systemroot)\capolicy.inf", 290 | (Get-Content -Path $CaPolFile -Encoding UTF8 -Raw), 291 | [System.Text.Encoding]::GetEncoding('iso-8859-1') 292 | ) 293 | 294 | [void](New-Item -Path $CaDbDir -ItemType Directory -ErrorAction SilentlyContinue) 295 | [void](New-Item -Path $CaDbLogDir -ItemType Directory -ErrorAction SilentlyContinue) 296 | 297 | $Arguments = @{ 298 | CACommonName = $CaName 299 | DatabaseDirectory = $CaDbDir 300 | LogDirectory = $CaDbLogDir 301 | HashAlgorithm = $HashAlgorithm 302 | CryptoProviderName = "$($KeyAlgorithm)#$($KspName)" 303 | OverwriteExistingKey = $True 304 | OverwriteExistingDatabase = $True 305 | Force = $True 306 | } 307 | 308 | Switch ($CaType) { 309 | 310 | $ENUM_STANDALONE_ROOTCA { $Arguments.Add("CAType", "StandaloneRootCA") } 311 | $ENUM_ENTERPRISE_ROOTCA { $Arguments.Add("CAType", "EnterpriseRootCA") } 312 | $ENUM_STANDALONE_SUBCA { $Arguments.Add("CAType", "StandaloneSubordinateCA") } 313 | $ENUM_ENTERPRISE_SUBCA { $Arguments.Add("CAType", "EnterpriseSubordinateCA") } 314 | } 315 | 316 | Switch ($KeyAlgorithm) { 317 | 318 | "ECDSA_P256" { $Arguments.Add("KeyLength", 256) } 319 | "ECDSA_P384" { $Arguments.Add("KeyLength", 384) } 320 | "ECDSA_P521" { $Arguments.Add("KeyLength", 521) } 321 | "RSA" { $Arguments.Add("KeyLength", $KeyLength) } 322 | } 323 | 324 | If ($DnSuffix) { 325 | $Arguments.Add("CADistinguishedNameSuffix", $DnSuffix) 326 | } 327 | 328 | If ($AllowAdminInteraction.IsPresent) { 329 | $Arguments.Add("AllowAdministratorInteraction", $True) 330 | } 331 | 332 | If (($CaType -eq $ENUM_STANDALONE_ROOTCA) -or ($CaType -eq $ENUM_ENTERPRISE_ROOTCA)) { 333 | $Arguments.Add("ValidityPeriod", $CaCertValidityPeriod) 334 | $Arguments.Add("ValidityPeriodUnits", $CaCertValidityPeriodUnits) 335 | } 336 | 337 | If (($CaType -eq $ENUM_STANDALONE_SUBCA) -or ($CaType -eq $ENUM_ENTERPRISE_SUBCA)) { 338 | $Arguments.Add("OutputCertRequestFile", $CsrFile) 339 | } 340 | 341 | # This Installs and configures the CA Role 342 | Try { 343 | [void](Install-WindowsFeature -Name Adcs-Cert-Authority -IncludeManagementTools) 344 | [void](Install-AdcsCertificationAuthority @Arguments) 345 | } 346 | Catch { 347 | Write-Error -Message $PSItem.Exception.Message 348 | return 349 | } 350 | 351 | # Steps specific for Enterprise CAs 352 | If (($CaType -eq $ENUM_ENTERPRISE_ROOTCA) -or ($CaType -eq $ENUM_ENTERPRISE_SUBCA)) { 353 | 354 | # To set the policy configuration to enable audit of template events, run the following command: 355 | # From 356 | certutil -setreg policy\EditFlags +EDITF_AUDITCERTTEMPLATELOAD 357 | 358 | # Allow Renewal on Behalf of, which is required for Key-based Renewal 359 | If ($AllowRenewalOnBehalfOf.IsPresent) { 360 | certutil -setreg policy\EditFlags +EDITF_ENABLERENEWONBEHALFOF 361 | } 362 | } 363 | 364 | # Steps specific for Standalone CAs 365 | If (($CaType -eq $ENUM_STANDALONE_ROOTCA) -or ($CaType -eq $ENUM_STANDALONE_SUBCA)) { 366 | 367 | # Settings required to issue Certificates compliant to BSI requirements 368 | If (-not $LegacyProfile.IsPresent) { 369 | 370 | # Remove Digital Signature from the Key Usage Extension 371 | # Make the Key Usage Extension Critical 372 | certutil -setreg policy\EditFlags -EDITF_ADDOLDKEYUSAGE 373 | } 374 | 375 | # Remove Microsoft specific Extensions from issued Certificates 376 | If (-not $KeepProprietaryExtensions.IsPresent) { 377 | 378 | certutil -setreg policy\DisableExtensionList +$szOID_ENROLL_CERTTYPE_EXTENSION 379 | } 380 | } 381 | 382 | # Remove Microsoft specific Extensions from issued Certificates 383 | If (-not $KeepProprietaryExtensions.IsPresent) { 384 | 385 | certutil -setreg policy\DisableExtensionList +$szOID_CERTSRV_CA_VERSION 386 | certutil -setreg policy\DisableExtensionList +$szOID_CERTSRV_PREVIOUS_CERT_HASH 387 | certutil -setreg policy\DisableExtensionList +$szOID_APPLICATION_CERT_POLICIES 388 | } 389 | 390 | # Apply Path Length Constraint 391 | If ($CaPathLength) { 392 | certutil -setreg Policy\CAPathLength $CaPathLength 393 | } 394 | 395 | If ($DsConfigDn) { 396 | certutil -setreg CA\DSConfigDN $DsConfigDn 397 | } 398 | 399 | If ($NoEnforceX500NameLengths.IsPresent) { 400 | certutil -setreg CA\EnforceX500NameLengths 0 401 | } 402 | 403 | certutil -setreg CA\Loglevel $LogLevel 404 | certutil -setreg CA\CRLPeriodUnits $CrlPeriodUnits 405 | certutil -setreg CA\CRLPeriod $CrlPeriod 406 | certutil -setreg CA\CRLDeltaPeriodUnits $CrlDeltaPeriodUnits 407 | certutil -setreg CA\CRLDeltaPeriod $CrlDeltaPeriod 408 | certutil -setreg CA\CRLOverlapUnits $CrlOverlapUnits 409 | certutil -setreg CA\CRLOverlapPeriod $CrlOverlapPeriod 410 | certutil -setreg CA\CRLDeltaOverlapUnits $CrlDeltaOverlapUnits 411 | certutil -setreg CA\CRLDeltaOverlapPeriod $CrlDeltaOverlapPeriod 412 | certutil -setreg CA\ValidityPeriodUnits $ValidityPeriodUnits 413 | certutil -setreg CA\ValidityPeriod $ValidityPeriod 414 | certutil -setreg CA\EncryptionCSP\Provider $EncryptionCsp 415 | 416 | # Enable Auditing at the CA Level 417 | certutil -setreg CA\Auditfilter $AuditFilter 418 | 419 | # Enable Auditing at the OS Level 420 | If ($AuditFilter -gt 0) { 421 | Write-Warning -Message "Configuring local Audit Policy to enable Object Access Auditing for Certification Services. You should enforce this setting via a Group Policy!" 422 | auditpol /set /subcategory:"{0CCE9221-69AE-11D9-BED3-505054503030}" /success:enable /failure:enable 423 | } 424 | 425 | # Clear the existing AIA Configuration, leaving only the default local Path 426 | Get-CaAuthorityInformationAccess | Where-Object { 427 | -not ($_.Uri -match ($DIRECTORY_CERTENROLL).Replace("\","\\")) 428 | } | Foreach-Object -Process { 429 | Write-Verbose "Removing Default AIA $($_.Uri)" 430 | [void](Remove-CaAuthorityInformationAccess $_.Uri -Force) 431 | } 432 | 433 | ForEach ($Uri in $Aia) { 434 | 435 | $Arguments = @{ 436 | Force = $True 437 | Uri = $Uri.Trim() 438 | } 439 | 440 | # Web Urls 441 | If ($Uri.StartsWith("http://")) { 442 | 443 | If ($Uri.EndsWith("/ocsp")) { 444 | 445 | # Allow requesting Certificates with an AKI Extension (for OCSP Response Signing Certificates) 446 | # https://technet.microsoft.com/en-us/library/cc754774(v=ws.11).aspx 447 | certutil -setreg CA\UseDefinedCACertInRequest 1 448 | 449 | $Arguments.Add("AddToCertificateOcsp", $True) 450 | } 451 | Else { 452 | $Arguments.Add("AddToCertificateAia", $True) 453 | } 454 | } 455 | 456 | # LDAP Paths 457 | If ($Uri.StartsWith("ldap://")) { 458 | $Arguments.Add("AddToCertificateAia", $True) 459 | } 460 | 461 | [void](Add-CaAuthorityInformationAccess @Arguments) 462 | } 463 | 464 | # Clear the existing CDP Configuration, leaving only the default local Path 465 | Get-CaCrlDistributionPoint | Where-Object { 466 | -not ($_.Uri -match ($DIRECTORY_CERTENROLL).Replace("\","\\")) 467 | } | Foreach-Object -Process { 468 | Write-Verbose "Removing Default CDP $($_.Uri)" 469 | [void](Remove-CaCrlDistributionPoint $_.Uri -Force) 470 | } 471 | 472 | ForEach ($Uri in $Cdp) { 473 | 474 | $Arguments = @{ 475 | Force = $True 476 | Uri = $Uri.Trim() 477 | } 478 | 479 | # Web Urls 480 | If ($Uri.StartsWith("http://")) { 481 | $Arguments.Add("AddToCertificateCdp", $True) 482 | $Arguments.Add("AddToFreshestCrl", $True) 483 | } 484 | 485 | # LDAP Paths 486 | If ($Uri.StartsWith("ldap://")) { 487 | $Arguments.Add("AddToCertificateCdp", $True) 488 | $Arguments.Add("AddToCrlCdp", $True) 489 | $Arguments.Add("AddToFreshestCrl", $True) 490 | 491 | # Steps specific for Enterprise CAs 492 | If (($CaType -eq $ENUM_ENTERPRISE_ROOTCA) -or ($CaType -eq $ENUM_ENTERPRISE_SUBCA)) { 493 | $Arguments.Add("PublishToServer", $True) 494 | $Arguments.Add("PublishDeltaToServer", $True) 495 | } 496 | } 497 | 498 | # UNC or File System Path 499 | If ($Uri -match "\\") { 500 | $Arguments.Add("PublishToServer", $True) 501 | $Arguments.Add("PublishDeltaToServer", $True) 502 | } 503 | 504 | [void](Add-CaCrlDistributionPoint @Arguments) 505 | } 506 | 507 | If (($CaType -eq $ENUM_ENTERPRISE_ROOTCA) -or ($CaType -eq $ENUM_STANDALONE_ROOTCA)) { 508 | 509 | # Restart Certificate Services to reflect new Configuration 510 | 511 | Stop-Service -Name CertSvc 512 | 513 | # Implement a delay if not using the default Software KSP 514 | # Some HSM KSPs need some time to clean up their stuff before the Service can be started again 515 | If ((Get-AdcsKspName) -ne "Microsoft Software Key Storage Provider") { 516 | Write-Warning -Message "Waiting $CA_SERVICE_STOP_WAIT_SECONDS Seconds for KSPs to close their Handles..." 517 | Start-Sleep -Second $CA_SERVICE_STOP_WAIT_SECONDS 518 | } 519 | 520 | Start-Service -Name CertSvc 521 | } 522 | 523 | # We assume that there is an Interaction needed with the CA Service when this is enabled 524 | If ($AllowAdminInteraction.IsPresent) { 525 | Write-Warning -Message "The Active Directory Certificates Service Startup Type was set to Manual due to required Administrator Interaction Setting." 526 | Set-Service -Name CertSvc -StartupType Manual 527 | } 528 | 529 | If (($CaType -eq $ENUM_ENTERPRISE_ROOTCA) -or ($CaType -eq $ENUM_ENTERPRISE_SUBCA)) { 530 | 531 | Write-Warning -Message "It is advised that you reboot the machine after the deployment has finished to reflect its newly-added Domain Group memberships." 532 | } 533 | } 534 | 535 | end {} 536 | } -------------------------------------------------------------------------------- /lib/Test-AdcsServiceAvailability.ps1: -------------------------------------------------------------------------------- 1 | Function Test-AdcsServiceAvailability { 2 | 3 | [cmdletbinding()] 4 | param() 5 | 6 | begin { 7 | # https://docs.microsoft.com/en-us/windows/desktop/api/certcli/nf-certcli-icertconfig-getconfig 8 | New-Variable -Option Constant -Name CC_LOCALCONFIG -Value 0x00000003 9 | 10 | # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/87135fdf-d681-4de0-9953-a0399b6902ee 11 | New-Variable -Option Constant -Name CR_PROP_CANAME -Value 0x00000006 12 | 13 | # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nf-certcli-icertrequest2-getfullresponseproperty 14 | New-Variable -Option Constant -Name PROPTYPE_STRING -Value 4 15 | } 16 | 17 | process { 18 | 19 | Try { 20 | # We determine the Config String of the locally installed CA 21 | # https://docs.microsoft.com/en-us/windows/desktop/api/certcli/nf-certcli-icertconfig-getconfig 22 | $CertConfig = New-Object -ComObject CertificateAuthority.Config 23 | $ConfigString = $CertConfig.GetConfig($CC_LOCALCONFIG) 24 | 25 | # Then we build the ICertAdmin2 Interface 26 | $CertAdmin = New-Object -ComObject CertificateAuthority.Admin.1 27 | } 28 | Catch { 29 | Return $False 30 | } 31 | 32 | 33 | Try { 34 | # Then we try to query the CA Name over the ICertAdmin2 Interface 35 | # https://docs.microsoft.com/en-us/windows/win32/api/certadm/nn-certadm-icertadmin2# 36 | $PropIndex = 0 37 | $Flags = 0 38 | [void]($CertAdmin.GetCAProperty( 39 | $ConfigString, 40 | $CR_PROP_CANAME, 41 | $PropIndex, 42 | $PROPTYPE_STRING, 43 | $Flags) 44 | ) 45 | Return $True 46 | } 47 | Catch { 48 | Return $False 49 | } 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /lib/Test-Flag.ps1: -------------------------------------------------------------------------------- 1 | function Test-Flag { 2 | 3 | [cmdletbinding()] 4 | param ( 5 | [Parameter(Mandatory = $True)] 6 | [Int] 7 | $Flags, 8 | 9 | [Parameter(Mandatory = $True)] 10 | [Int] 11 | $Flag 12 | ) 13 | 14 | If (($Flags -bAnd $Flag) -eq $Flag) { 15 | return $True 16 | } 17 | Else { 18 | return $False 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /lib/Test-KspAvailability.ps1: -------------------------------------------------------------------------------- 1 | Function Test-KspAvailability { 2 | 3 | param ( 4 | [Parameter(Mandatory=$True)] 5 | [string] 6 | $Name 7 | ) 8 | 9 | process { 10 | 11 | # Seems that there is no Enumerate Method or the like to test the actual presence of a CSP/KSP. 12 | # Thus we simply try to initialize with the given KSP name. 13 | # If this does not fail, we can assume that KSP is installed on the System. 14 | 15 | # https://github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/security/certservices/certenroll/createsimplecertrequest/CreateSimpleCertRequest.cs 16 | $CspInformationObject = New-Object -ComObject X509Enrollment.CCspInformation 17 | 18 | Try { 19 | $CspInformationObject.InitializeFromName($Name) 20 | return $True 21 | } 22 | Catch { 23 | return $False 24 | } 25 | } 26 | } --------------------------------------------------------------------------------