Hi,
I am working on a PowerShell script for the Forti-ADC to upload PFX-certificates. The API is working fine and I can GET information with API-calls from the Forti-ADC with PowerShell. The only thing I cannot get to work is uploading a certificate
I found a way to upload certificates via Bash, as this is written in the manual (https://docs.fortinet.com/document/fortiadc/6.0.1/rest-api-programming-guide). This is working fine, but I could not succeed in doing the same with PowerShell.
The request looks like this (session details not added).
$ClearTextPfxPassword = "password"
$URI = "https://1.2.3.4/api/upload/certificate_local"
$Body = @{}
$Body.add("vdom", "root")
$Body.add("mkey", "ScriptName")
$Body.add("type", "PKCS12")
$Body.add("passwd", $ClearTextPfxPassword)
$Body.add("cert", "certificateFilename.pfx")
$ResultUploadCertificate = Invoke-webrequest -Uri $URI -Method Post -Headers $Headers -form $Body -WebSession $session -SkipCertificateCheck -verbose
The response looks like this:
PS Microsoft.PowerShell.Core\FileSystem::> $ResultUploadCertificate
StatusCode : 200
StatusDescription : OK
Content : {"payload":-2001}
RawContent : HTTP/1.1 200 OK
Date: Tue, 30 Feb 2022 07:42:01 GMT
Connection: keep-alive
Set-Cookie: last_access_time=1644444444; Path=/; SameSite=strict; HttpOnly; Secure
X-XSS-Protection: 1; mode=block
Conte…
Headers : {[Date, System.String[]], [Connection, System.String[]], [Set-Cookie, System.String[]], [X-XSS-Protection, System.String[]]…}
Images : {}
InputFields : {}
Links : {}
RawContentLength : 17
RelationLink : {}
The bash variant looks like this and is working:
curl -v -F 'mkey=ScriptTestName' -F 'vdom=root' -F 'type=PKCS12' -F 'passwd=password' -F 'cert=@certificateFilename.pfx' -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxx" -H "Cookie: last_access_time=164444444" --insecure https://1.2.3.4/api/upload/certificate_local
I tried several things, like:
Is someone able to inform what is wrong with the PS-script and how I can get it to work?
Nominating a forum post submits a request to create a new Knowledge Article based on the forum post topic. Please ensure your nomination includes a solution within the reply.
Created on 02-24-2022 10:17 AM
Hello @BJBee ,
Thank you for posting to Fortinet Community Forums. We would be having someone answer this query on the post. Thank you for your patience.
Created on 02-25-2022 01:51 PM
Hello @BJBee,
Can you confirm if the WAF is enabled on the device?
Hi BJBee. When using Postman to upload certificate files, I've had to add this HTTP header. Maybe the bash script does it automatically and the PowerShell does not?
Content-Type: "multipart/form-data; boundary=--------------------------"
The reason is that the POST consists of both an HTML form with the parameters, and then the binary part being the upload of the actual PFX file.
If you enable HTTP management on ADC, and disable redirect to HTTPS, you can make a packet capture to see what the HTTP request actually looks like, and see if this may be a hint.
I have been struggling to get this to work, but finally did. Below is the script I am using to login and upload the PFX via the API in Powershell. The important things to note is the FormDataTemplate section that manually crafts the multipart/form-data body. Also, the encoding for the file is important, I use ISO-8859-1 because it is encoded using a single byte unlike UTF-8 and others. I tried all sorts of ones until I found ISO-8859-1.
$PFXFilePath = 'C:\temp\cert.pfx'
$PFXFileName = 'cert.pfx'
$PFXPassword = "yourpfxpassword"
$ADCCertName = "thenameofthecertintheADC"
$ADCUsername = "YourADCUser"
$ADCPassword = "yourADCUSerPassword"
$ADCHostname = "youradchostname"
$loginheaders = @{
'Content-Type' = 'application/json'
'Accept' = 'application/json'
}
$loginbody = @{
'username'=$ADCUsername
'password'=$ADCPassword
}
$LoginRequest = Invoke-WebRequest -Uri "https://$ADCHostname/api/user/login" -Headers $loginheaders -Method Post -Body ($loginbody|ConvertTo-Json) -SessionVariable session
$token = (ConvertFrom-Json $([String]::new($LoginRequest.Content))).token
$boundary = "Thisistheuniqueboundarystring"
$UploadHeaders = @{
'Content-Type' = "multipart/form-data; boundary=$boundary"
'Accept' = '*/*'
'Authorization'='Bearer ' + $token
}
$PFXFileBytes = [System.IO.File]::ReadAllBytes($PFXFilePath)
$enc = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
$PFXFileEncoded = $enc.GetString($PFXFileBytes)
#creating the formdata manually
$FormDataTemplate = "
--$boundary
Content-Disposition: form-data; name=""mkey""
$ADCCertName
--$boundary
Content-Disposition: form-data; name=""vdom""
global
--$boundary
Content-Disposition: form-data; name=""type""
PKCS12
--$boundary
Content-Disposition: form-data; name=""passwd""
$PFXPassword
--$boundary
Content-Disposition: form-data; name=""cert""; filename=""$PFXFileName""
Content-Type: application/octet-stream
"+$PFXFileEncoded+"
--$boundary--"
$UploadRequest = Invoke-webrequest -Uri "https://$ADCHostname/api/upload/certificate_local" -Headers $UploadHeaders -Body $FormDataTemplate -Method Post -WebSession $session
You shouldn't have any problems with the above and it should all work, this was built for Powershell v5 but tested and worked in v7 as well. The spacing between the boundaries is important and probably should not be changed. If you are getting a payload -2001 or payload multipart upload fail, then the formatting of the multipart body is wrong and has an extra newline, space, etc. If you are getting a payload -167 then that means it can't decrypt and use the PFX, so that means the encoding on the file is wrong or the password is incorrect. At least this is what I found those errors to mean. I don't know what the official meaning is, it would be nice if the documentation was a little more robust for things like that.
Has the uri for the certificate upload changed in recent firmware? I have a FortiADC on v7.4 and api/upload/certificate_local returns a 404. I don't have access to the Fortinet developer portal to see any recent API documentation.
Finally back around at working on this, and not sure why I was getting a 404 - but kudos to securityOTC for this script, it works perfectly and I'll be using it to upload ACME issued wildcard certificates.
A hint I'll leave for the next person who finds this thread. If you can't find the API method to use, or the parameters its expecting, open your browser Dev Tools and capture the actions through the webui. It will capture the URIs and the parameters / JSON that you need to pass.
Select Forum Responses to become Knowledge Articles!
Select the “Nominate to Knowledge Base” button to recommend a forum post to become a knowledge article.
User | Count |
---|---|
1705 | |
1093 | |
752 | |
446 | |
230 |
The Fortinet Security Fabric brings together the concepts of convergence and consolidation to provide comprehensive cybersecurity protection for all users, devices, and applications and across all network edges.
Copyright 2024 Fortinet, Inc. All Rights Reserved.