From 2873ab07abbe5071b648423a865a8c8f159eadb3 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 9 Nov 2021 14:57:17 -0500 Subject: [PATCH] Fix #37, add application base custom fields (#38) * fix #37 * support application base custom fields * release prep * release prep * cert import fixes * help update * add ca attribs when creating new cert --- CHANGELOG.md | 6 +++ RELEASE.md | 6 ++- VenafiPS/Public/Get-TppCustomField.ps1 | 7 ++- VenafiPS/Public/Import-TppCertificate.ps1 | 66 ++++++++++++++++------- VenafiPS/Public/New-TppCertificate.ps1 | 47 ++++++++++++---- VenafiPS/Public/New-VenafiSession.ps1 | 8 ++- 6 files changed, 98 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 584684ad..4eade045 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 3.3.1 +- Remove validation/limitation from `Get-TppCustomField` to only retrieve classes of type X509 Certificate and Device +- Retrieve Application Base custom fields during `New-VenafiSession` +- Fix parameter sets in `Import-TppCertificate` requiring PrivateKey be provided with PKCS#12 certificate, [#37](https://github.com/gdbarron/VenafiPS/issues/37) +- Add `-CertificateAuthorityAttribute` to `New-TppCertificate` to submit values to the CA during enrollment + ## 3.3.0 - Add support for local token/key storage with [PowerShell SecretManagement](https://devblogs.microsoft.com/powershell/secretmanagement-and-secretstore-are-generally-available/). Store your access or refresh token securely and have VenafiPS use it to create a new session. - Add `Get-TppClassAttribute` to list all attributes for a specific class. Helpful for attribute validation and getting values for all attributes. diff --git a/RELEASE.md b/RELEASE.md index ddf0fa43..536560f5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,2 +1,4 @@ -- Add support for local token/key storage with [PowerShell SecretManagement](https://devblogs.microsoft.com/powershell/secretmanagement-and-secretstore-are-generally-available/). Store your access or refresh token securely and have VenafiPS use it to create a new session. -- Add `Get-TppClassAttribute` to list all attributes for a specific class. Helpful for attribute validation and getting values for all attributes. \ No newline at end of file +- Remove validation/limitation from `Get-TppCustomField` to only retrieve classes of type X509 Certificate and Device +- Retrieve Application Base custom fields during `New-VenafiSession` +- Fix parameter sets in `Import-TppCertificate` requiring PrivateKey be provided with PKCS#12 certificate, [#37](https://github.com/gdbarron/VenafiPS/issues/37) +- Add `-CertificateAuthorityAttribute` to `New-TppCertificate` to submit values to the CA during enrollment diff --git a/VenafiPS/Public/Get-TppCustomField.ps1 b/VenafiPS/Public/Get-TppCustomField.ps1 index 1247c1f8..1301378e 100644 --- a/VenafiPS/Public/Get-TppCustomField.ps1 +++ b/VenafiPS/Public/Get-TppCustomField.ps1 @@ -3,10 +3,10 @@ Get custom field details .DESCRIPTION -Get details about custom fields for either certificates or devices +Get details about custom fields .PARAMETER Class -Class to get details on. Value can be either Device or X509 Certificate +Class to get details on .PARAMETER VenafiSession Session object created from New-VenafiSession method. The value defaults to the script session object $VenafiSession. @@ -51,8 +51,7 @@ function Get-TppCustomField { [CmdletBinding()] param ( - [Parameter(Mandatory)] - [ValidateSet('Device', 'X509 Certificate')] + [Parameter(Mandatory, ValueFromPipeline)] [string] $Class, [Parameter()] diff --git a/VenafiPS/Public/Import-TppCertificate.ps1 b/VenafiPS/Public/Import-TppCertificate.ps1 index 7d219aa0..db550ac8 100644 --- a/VenafiPS/Public/Import-TppCertificate.ps1 +++ b/VenafiPS/Public/Import-TppCertificate.ps1 @@ -26,10 +26,12 @@ If not provided and the CN is also missing, the name becomes the first Domain Na Finally, if none of the above are found, the serial number is used. .PARAMETER PrivateKey -The private key data. Requires a Password. For a PEM certificate, the private key is in either the RSA or PKCS#8 format. If the CertificateData field contains a PKCS#12 formatted certificate, this parameter is ignored because only one private key is allowed. +Private key data; requires a value for Password. +For a PEM certificate, the private key is in either the RSA or PKCS#8 format. +Do not provide for a PKCS#12 certificate as the private key is already included. .PARAMETER Password -Password required when including a private key. +Password required if the certificate has a private key. .PARAMETER Reconcile Controls certificate and corresponding private key replacement. @@ -55,8 +57,8 @@ None .OUTPUTS TppObject, if PassThru provided -.NOTES -Must have Master Admin permission or must have View, Read, Write, Create and Private Key Write permission to the Certificate object. +.LINK +https://docs.venafi.com/Docs/current/TopNav/Content/SDK/WebSDK/r-SDK-POST-Certificates-Import.php #> function Import-TppCertificate { [CmdletBinding(DefaultParameterSetName = 'ByFile')] @@ -67,7 +69,8 @@ function Import-TppCertificate { [ValidateScript( { if ( $_ | Test-TppDnPath ) { $true - } else { + } + else { throw "'$_' is not a valid Policy path" } })] @@ -79,7 +82,8 @@ function Import-TppCertificate { [ValidateScript( { if ( $_ | Test-Path ) { $true - } else { + } + else { throw "'$_' is not a valid path" } })] @@ -87,20 +91,27 @@ function Import-TppCertificate { [Parameter(Mandatory, ParameterSetName = 'ByData')] [Parameter(Mandatory, ParameterSetName = 'ByDataWithPrivateKey')] + [ValidateNotNullOrEmpty()] [String] $CertificateData, [Parameter()] + [ValidateNotNullOrEmpty()] [String] $Name, [Parameter()] + [ValidateNotNullOrEmpty()] [Hashtable] $EnrollmentAttribute, [Parameter(Mandatory, ParameterSetName = 'ByFileWithPrivateKey')] [Parameter(Mandatory, ParameterSetName = 'ByDataWithPrivateKey')] + [ValidateNotNullOrEmpty()] [String] $PrivateKey, + [Parameter(ParameterSetName = 'ByFile')] + [Parameter(ParameterSetName = 'ByData')] [Parameter(Mandatory, ParameterSetName = 'ByFileWithPrivateKey')] [Parameter(Mandatory, ParameterSetName = 'ByDataWithPrivateKey')] + [ValidateNotNullOrEmpty()] [SecureString] $Password, [Parameter()] @@ -117,28 +128,43 @@ function Import-TppCertificate { $VenafiSession.Validate() | Out-Null + } + + process { + + Write-Verbose $PSCmdlet.ParameterSetName + if ( $PSBoundParameters.ContainsKey('CertificatePath') ) { # get cert data from file - $CertificateData = Get-Content -Path $CertificatePath -Raw + if ($PSVersionTable.PSVersion.Major -lt 6) { + $cert = Get-Content $CertificatePath -Encoding Byte + } + else { + $cert = Get-Content $CertificatePath -AsByteStream + } + + $thisCertData = [System.Convert]::ToBase64String($cert) + } + else { + $thisCertData = $CertificateData } $params = @{ VenafiSession = $VenafiSession - Method = 'Post' - UriLeaf = 'certificates/import' - Body = @{ + Method = 'Post' + UriLeaf = 'certificates/import' + Body = @{ PolicyDN = $PolicyPath - CertificateData = $CertificateData + CertificateData = $thisCertData } } if ( $PSBoundParameters.ContainsKey('EnrollmentAttribute') ) { $updatedAttribute = @($EnrollmentAttribute.GetEnumerator() | ForEach-Object { @{'Name' = $_.name; 'Value' = $_.value } }) $params.Body.CASpecificAttributes = $updatedAttribute - } - if ( $PSBoundParameters.ContainsKey('Reconcile') ) { + if ( $Reconcile.IsPresent ) { $params.Body.Reconcile = 'true' } @@ -146,20 +172,20 @@ function Import-TppCertificate { $params.Body.ObjectName = $Name } + + if ( $PSBoundParameters.ContainsKey('Password') ) { + $params.Body.Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)) + } + if ( $PSBoundParameters.ContainsKey('PrivateKey') ) { $params.Body.PrivateKeyData = $PrivateKey - $plainTextPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)) - $params.Body.Password = $plainTextPassword } $response = Invoke-TppRestMethod @params Write-Verbose ('Successfully imported certificate') - if ( $PassThru ) { - $response.CertificateDN | Get-TppObject + if ( $PassThru.IsPresent ) { + Get-TppObject -Guid $response.Guid } } - - process { - } } diff --git a/VenafiPS/Public/New-TppCertificate.ps1 b/VenafiPS/Public/New-TppCertificate.ps1 index 0d5a9476..dabaddf3 100644 --- a/VenafiPS/Public/New-TppCertificate.ps1 +++ b/VenafiPS/Public/New-TppCertificate.ps1 @@ -22,6 +22,10 @@ Valid values include 'Code Signing', 'Device', 'Server' (same as default), and ' .PARAMETER CertificateAuthorityDN The Distinguished Name (DN) of the Trust Protection Platform Certificate Authority Template object for enrolling the certificate. If the value is missing, use the default CADN +.PARAMETER CertificateAuthorityAttribute +Name/value pairs providing any CA attributes to store with the Certificate object. +During enrollment, these values will be submitted to the CA. + .PARAMETER ManagementType The level of management that Trust Protection Platform applies to the certificate: - Enrollment: Default. Issue a new certificate, renewed certificate, or key generation request to a CA for enrollment. Do not automatically provision the certificate. @@ -80,7 +84,8 @@ function New-TppCertificate { [ValidateScript( { if ( $_ | Test-TppDnPath ) { $true - } else { + } + else { throw "'$_' is not a valid DN path" } })] @@ -104,7 +109,8 @@ function New-TppCertificate { [ValidateScript( { if ( $_ | Test-TppDnPath ) { $true - } else { + } + else { throw "'$_' is not a valid DN path" } })] @@ -112,6 +118,9 @@ function New-TppCertificate { [Alias('CADN')] [String] $CertificateAuthorityPath, + [Parameter()] + [Hashtable] $CertificateAuthorityAttribute, + [Parameter()] [TppManagementType] $ManagementType, @@ -145,7 +154,8 @@ function New-TppCertificate { 'Email' { try { $null = [mailaddress]$thisValue - } catch { + } + catch { ('''{0}'' is not a valid email' -f $thisValue) } } @@ -161,7 +171,8 @@ function New-TppCertificate { 'IPAddress' { try { $null = [ipaddress]$thisValue - } catch { + } + catch { ('''{0}'' is not a valid IP Address' -f $thisValue) } } @@ -181,14 +192,27 @@ function New-TppCertificate { $params = @{ VenafiSession = $VenafiSession - Method = 'Post' - UriLeaf = 'certificates/request' - Body = @{ + Method = 'Post' + UriLeaf = 'certificates/request' + Body = @{ PolicyDN = $Path Origin = 'VenafiPS' - CASpecificAttributes = @{ - 'Name' = 'Origin' - 'Value' = 'VenafiPS' + CASpecificAttributes = @( + @{ + 'Name' = 'Origin' + 'Value' = 'VenafiPS' + } + ) + } + } + + if ( $PSBoundParameters.ContainsKey('CertificateAuthorityAttribute') ) { + $CertificateAuthorityAttribute.GetEnumerator() | ForEach-Object { + + $params.Body.CASpecificAttributes += + @{ + 'Name' = $_.Key + 'Value' = $_.Value } } } @@ -244,7 +268,8 @@ function New-TppCertificate { [TppObject] $returnObject } - } catch { + } + catch { Write-Error $_ continue } diff --git a/VenafiPS/Public/New-VenafiSession.ps1 b/VenafiPS/Public/New-VenafiSession.ps1 index 640a1cb8..fbee65e7 100644 --- a/VenafiPS/Public/New-VenafiSession.ps1 +++ b/VenafiPS/Public/New-VenafiSession.ps1 @@ -503,11 +503,9 @@ function New-VenafiSession { # only applicable to tpp if ( $PSCmdlet.ParameterSetName -notin 'VaasKey', 'VaultVaasKey' ) { $newSession.Version = (Get-TppVersion -VenafiSession $newSession -ErrorAction SilentlyContinue) - $certFields = Get-TppCustomField -VenafiSession $newSession -Class 'X509 Certificate' -ErrorAction SilentlyContinue - $deviceFields = Get-TppCustomField -VenafiSession $newSession -Class 'Device' -ErrorAction SilentlyContinue - $allFields = $certFields.Items - $allFields += $deviceFields.Items | Where-Object { $_.Guid -notin $allFields.Guid } - $newSession.CustomField = $allFields + $certFields = 'X509 Certificate', 'Device', 'Application Base' | Get-TppCustomField -VenafiSession $newSession -ErrorAction SilentlyContinue + # make sure we remove duplicates + $newSession.CustomField = $certFields.Items | Sort-Object -Property Guid -Unique } if ( $PassThru ) {