Skip to content

Commit

Permalink
export format update
Browse files Browse the repository at this point in the history
  • Loading branch information
Greg Brownstein committed Nov 7, 2023
1 parent 7955983 commit f9680ee
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 84 deletions.
2 changes: 1 addition & 1 deletion VenafiPS/Private/New-VcSearchQuery.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function New-VcSearchQuery {

# first item may be the operator or a filter
# if so, pull it off the list and process the rest
if ($Filter[0].GetType().Name -eq 'String' -and $Filter[0] -in 'AND', 'OR') {
if ($Filter[0] -is 'String' -and $Filter[0] -in 'AND', 'OR') {
$operator = $Filter[0].ToUpper()
$loopFilter = $Filter | Select-Object -Skip 1
$loopFilter = @(, $loopFilter)
Expand Down
30 changes: 8 additions & 22 deletions VenafiPS/Public/Export-VcCertificate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,19 @@ function Export-VcCertificate {
Expoort certificate data from TLSPC
.DESCRIPTION
Export certificate data
Export certificate data in PEM format
.PARAMETER ID
Full path to the certificate
.PARAMETER Format
Certificate format, either Base64, Base64 (PKCS#8), DER, PKCS #7, or PKCS #12.
Defaults to Base64.
.PARAMETER OutPath
Folder path to save the certificate to. The name of the file will be determined automatically.
.PARAMETER IncludeChain
Include the certificate chain with the exported certificate. Not supported with DER format.
Include the certificate chain with the exported certificate.
.PARAMETER RootFirst
Use with -IncludeChain for TLSPC to return the root first instead of the end entity first
Use with -IncludeChain for TLSPC to return the root first instead of the end entity first which is the default
.PARAMETER ThrottleLimit
Limit the number of threads when running in parallel; the default is 100. Applicable to PS v7+ only.
Expand All @@ -37,19 +33,19 @@ function Export-VcCertificate {
PSCustomObject
.EXAMPLE
$certId | Export-VdcCertificate -VaasFormat PEM
$certId | Export-VcCertificate
Get certificate data from TLSPC
Export certificate data from TLSPC
.EXAMPLE
$cert | Export-VdcCertificate -TppFormat 'PKCS #7' -OutPath 'c:\temp'
$cert | Export-VcCertificate -OutPath '~/temp'
Get certificate data and save to a file
.EXAMPLE
$cert | Export-VdcCertificate -VaasFormat PEM -IncludeChain -RootFirst
$cert | Export-VcCertificate -IncludeChain -RootFirst
Get one or more certificates with the certificate chain included and the root first in the chain
Get certificate data with the certificate chain included and the root first in the chain
#>

[CmdletBinding(DefaultParameterSetName = 'Vaas')]
Expand All @@ -61,11 +57,6 @@ function Export-VcCertificate {
[Alias('certificateId')]
[string] $ID,

[Parameter(ParameterSetName = 'Vaas')]
[Parameter(ParameterSetName = 'VaasChain')]
[ValidateSet("DER", "PEM")]
[string] $Format = 'PEM',

[Parameter(ParameterSetName = 'VaasChain', Mandatory)]
[switch] $IncludeChain,

Expand Down Expand Up @@ -105,10 +96,6 @@ function Export-VcCertificate {
}

if ( $IncludeChain ) {
if ( $Format -in @('DER') ) {
throw "-IncludeChain is not supported with the DER Format"
}

$params.Body.chainOrder = 'EE_FIRST'
if ( $RootFirst ) {
$params.Body.chainOrder = 'ROOT_FIRST'
Expand All @@ -120,7 +107,6 @@ function Export-VcCertificate {
}

process {

$allCerts.Add($ID)
}

Expand Down
169 changes: 108 additions & 61 deletions VenafiPS/Public/Export-VdcCertificate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ function Export-VdcCertificate {
Label or alias to use. Permitted with Base64 and PKCS #12 formats. Required when exporting JKS.
.PARAMETER PrivateKeyPassword
Password required to include the private key. Not supported with DER or PKCS #7 formats.
Password required to include the private key.
You can either provide a String, SecureString, or PSCredential.
You must adhere to the following rules:
- Password is at least 12 characters.
- Comprised of at least three of the following:
Expand All @@ -37,6 +38,7 @@ function Export-VdcCertificate {
.PARAMETER KeystorePassword
Password required to retrieve the certificate in JKS format.
You can either provide a String, SecureString, or PSCredential.
You must adhere to the following rules:
- Password is at least 12 characters.
- Comprised of at least three of the following:
Expand Down Expand Up @@ -66,38 +68,73 @@ function Export-VdcCertificate {
Get certificate data
.EXAMPLE
$cert | Export-VdcCertificate -TppFormat 'PKCS #7' -OutPath 'c:\temp'
$cert | Export-VdcCertificate -'PKCS7' -OutPath 'c:\temp'
Get certificate data and save to a file
.EXAMPLE
$cert | Export-VdcCertificate -TppFormat 'PKCS #7' -IncludeChain
$cert | Export-VdcCertificate -'PKCS7' -IncludeChain
Get one or more certificates with the certificate chain included
.EXAMPLE
$cert | Export-VdcCertificate -TppFormat 'PKCS #12' -PrivateKeyPassword $cred.password
$cert | Export-VdcCertificate -'PKCS12' -PrivateKeyPassword 'mySecretPassword!'
Get one or more certificates with private key included
.EXAMPLE
$cert | Export-VdcCertificate -FriendlyName 'MyFriendlyName' -KeystorePassword $cred.password
$cert | Export-VdcCertificate -Jks -FriendlyName 'MyFriendlyName' -KeystorePassword $cred.password
Get certificates in JKS format. -TppFormat not needed since we know its JKS via -KeystorePassword.
Get certificates in JKS format.
#>

[CmdletBinding(DefaultParameterSetName = 'Tpp')]
[CmdletBinding(DefaultParameterSetName = 'Base64')]

param (

[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias('id')]
[string] $Path,

[Parameter(ParameterSetName = 'Tpp')]
[ValidateSet("Base64", "Base64 (PKCS #8)", "DER", "PKCS #7", "PKCS #12")]
[string] $Format = 'Base64',
[Parameter(ParameterSetName = 'Base64')]
[switch] $Base64,

[Parameter(Mandatory, ParameterSetName = 'Pkcs7')]
[switch] $Pkcs7,

[Parameter(Mandatory, ParameterSetName = 'Pkcs8')]
[switch] $Pkcs8,

[Parameter(Mandatory, ParameterSetName = 'Der')]
[switch] $Der,

[Parameter(Mandatory, ParameterSetName = 'Pkcs12')]
[switch] $Pkcs12,

[Parameter(Mandatory, ParameterSetName = 'Jks')]
[switch] $Jks,

[Parameter(ParameterSetName = 'Pkcs8')]
[Parameter(ParameterSetName = 'Pkcs12')]
[Parameter(ParameterSetName = 'Jks')]
[Alias('SecurePassword')]
[psobject] $PrivateKeyPassword,

[Parameter(ParameterSetName = 'Base64')]
[Parameter(ParameterSetName = 'Pkcs7')]
[Parameter(ParameterSetName = 'Pkcs8')]
[Parameter(ParameterSetName = 'Pkcs12')]
[Parameter(ParameterSetName = 'Jks')]
[switch] $IncludeChain,

[Parameter(ParameterSetName = 'Base64')]
[Parameter(ParameterSetName = 'Pkcs12')]
[Parameter(Mandatory, ParameterSetName = 'Jks')]
[string] $FriendlyName,

[Parameter(Mandatory, ParameterSetName = 'Jks')]
[psobject] $KeystorePassword,

[Parameter()]
[ValidateNotNullOrEmpty()]
Expand All @@ -111,20 +148,6 @@ function Export-VdcCertificate {
})]
[String] $OutPath,

[Parameter()]
[switch] $IncludeChain,

[Parameter(ParameterSetName = 'Tpp')]
[Parameter(Mandatory, ParameterSetName = 'TppJks')]
[string] $FriendlyName,

[Parameter()]
[Alias('SecurePassword')]
[Security.SecureString] $PrivateKeyPassword,

[Parameter(Mandatory, ParameterSetName = 'TppJks')]
[Security.SecureString] $KeystorePassword,

[Parameter()]
[int] $ThrottleLimit = 100,

Expand All @@ -135,80 +158,104 @@ function Export-VdcCertificate {
begin {
Test-VenafiSession -VenafiSession $VenafiSession -Platform 'VDC'

$allCerts = [System.Collections.Generic.List[string]]::new()
$allCerts = [System.Collections.Generic.List[hashtable]]::new()

$body = @{ Format = $Format }
$body = @{ Format = 'Base64' }
switch ($PSCmdlet.ParameterSetName) {
'Pkcs7' { $body.Format = 'PKCS #7' }
'Pkcs8' { $body.Format = 'Base64 (PKCS#8)' }
'Pkcs12' { $body.Format = 'PKCS #12' }
'Der' { $body.Format = 'DER' }
'Jks' { $body.Format = 'JKS' }
}

if ( $PSBoundParameters.ContainsKey('PrivateKeyPassword') ) {

# validate format to be able to export the private key
if ( $Format -in @("DER", "PKCS #7") ) {
throw "Format '$Format' does not support private keys"
}

$body.IncludePrivateKey = $true
$plainTextPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($PrivateKeyPassword))
$body.Password = $plainTextPassword

switch ($PrivateKeyPassword.GetType().Name) {
'String' { $body.Password = $PrivateKeyPassword }
'SecureString' { $body.Password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($PrivateKeyPassword)) }
'PSCredential' { $body.Password = $PrivateKeyPassword.GetNetworkCredential().Password }
Default { throw 'Unsupported type for -PrivateKeyPassword. Provide either a String, SecureString, or PSCredential.' }
}
}

if ( $PSBoundParameters.ContainsKey('KeystorePassword') ) {
$body.Format = 'JKS'
$plainTextPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($KeystorePassword))
$body.KeystorePassword = $plainTextPassword
switch ($KeystorePassword.GetType().Name) {
'String' { $body.Password = $KeystorePassword }
'SecureString' { $body.Password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni([System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($KeystorePassword)) }
'PSCredential' { $body.Password = $KeystorePassword.GetNetworkCredential().Password }
Default { throw 'Unsupported type for -KeystorePassword. Provide either a String, SecureString, or PSCredential.' }
}
}

if ( $PSBoundParameters.ContainsKey('FriendlyName') ) {
if ($Format -in @("Base64 (PKCS #8)", "DER", "PKCS #7")) {
throw "Only Base64, JKS, PKCS #12 formats support -FriendlyName parameter"
}

$body.FriendlyName = $FriendlyName
}

if ($IncludeChain) {
if ( $Format -in @('DER') ) {
throw "-IncludeChain is not supported with the DER Format"
}

$body.IncludeChain = $true
}

$body | Write-VerboseWithSecret

$splitCertificateDataFunction = 'function Split-CertificateData {{ {0} }}' -f (Get-Command Split-CertificateData | Select-Object -ExpandProperty Definition)
}

process {

$allCerts.Add(($Path | ConvertTo-VdcFullPath))
$body.CertificateDN = ($Path | ConvertTo-VdcFullPath)
$allCerts.Add(
@{
Body = $body
SplitCertificateDataFunction = $splitCertificateDataFunction
}
)
}

end {
Invoke-VenafiParallel -InputObject $allCerts -ScriptBlock {

# hashtables are reference types so the body must be cloned or the parent scope gets updated
$body = ($using:body).Clone()
. ([scriptblock]::Create($PSItem.SplitCertificateDataFunction))

$body.CertificateDN = $PSItem

$innerResponse = Invoke-VenafiRestMethod -Method 'Post' -UriLeaf 'certificates/retrieve' -Body $body
$thisBody = $PSItem.Body
$innerResponse = Invoke-VenafiRestMethod -Method 'Post' -UriLeaf 'certificates/retrieve' -Body $thisBody

$out = $innerResponse | Select-Object Filename, Format, @{
n = 'Path'
e = { $body.CertificateDN }
e = { $thisBody.CertificateDN }
},
@{
n = 'Error'
e = { $_.Status }
}

if ( $using:OutPath ) {
if ( $innerResponse.PSobject.Properties.name -contains "CertificateData" ) {
$outFile = Join-Path -Path $using:OutPath -ChildPath ($innerResponse.FileName.Trim('"'))
$bytes = [Convert]::FromBase64String($innerResponse.CertificateData)
[IO.File]::WriteAllBytes($outFile, $bytes)
Write-Verbose "Saved $outFile"
$out | Add-Member @{'OutPath' = $outFile }
if ( $innerResponse.CertificateData ) {

$splitData = Split-CertificateData -CertificateData $innerResponse.CertificateData

if ( $using:OutPath ) {
if ( $innerResponse.PSobject.Properties.name -contains "CertificateData" ) {
$outFile = Join-Path -Path $using:OutPath -ChildPath ($innerResponse.FileName.Trim('"'))
$bytes = [Convert]::FromBase64String($innerResponse.CertificateData)
[IO.File]::WriteAllBytes($outFile, $bytes)
Write-Verbose "Saved $outFile"
$out | Add-Member @{'OutPath' = $outFile }
}
}
else {
$out | Add-Member @{'CertificateData' = $innerResponse.CertificateData }
$out | Add-Member @{'CertPem' = $splitData.CertPem }

if ( $thisBody.IncludePrivateKey ) {
$out | Add-Member @{'KeyPem' = $splitData.KeyPem }
}

if ( $thisBody.IncludeChain -and $certPem.Count -gt 1 ) {
$out | Add-Member @{'ChainPem' = $splitData.CertPem[1..($splitData.CertPem.Count - 1)] }
}
}
}
else {
$out | Add-Member @{'CertificateData' = $innerResponse.CertificateData }
}

$out
Expand Down

0 comments on commit f9680ee

Please sign in to comment.