TZ400 SonicOS API - SSL Certificate
I'm trying to set up some automation for migrating my SSL certificates to Let's Encrypt certificates. After a few mishaps, I've finally gotten to where I can log in to our TZ400's API endpoint. I've done a little bit of testing so far, and it seems to work pretty well. That is, until I tried to generate a new CSR to submit to the Let's Encrypt CA for issuing a new SSL certificate. I've tried submitting a POST request to the /certificates/generate-signing-request endpoint, but I keep coming up with a 400 - Bad Request error.
There aren't a lot of specific examples available, so I'm wondering if I simply have my JSON formatted incorrectly, or something. Here's a slightly redacted version of what I'm trying to submit:
{ "certificates": { "generate_signing_request": [ { "alias": "test", "distinguished_name": { "element1": { "country": "US" }, "element2": { "state": "StateName" }, "element3": { "locality": "City Name" }, "element4": { "organization": "My Company Name" }, "element5": { "department": "Information Services" }, "element6": {}, "element7": {}, "element8": { "common_name": "test.example.com" } }, "alternate_name": {}, "signature_algorithm": "SHA256", "key": { "type": "RSA", "size": 1024 }, "generate": true } ] } }
I'm not sure what it is about the request that's failing, I've tried a few variations of the JSON above, including having the entire structure constructed with null values for the empty positions. For example:
"element1": { "country": "US", "state": null, "locality": null, "organization": null }
I've tried with lower-case algorithm and key type names (sha256/rsa) with the same results. I'm sure I'm simply overlooking something, but I just can't seem to get it to POST the request successfully. In my testing, I've been able to use the /address-objects/ipv4 endpoint to successfully retrieve information from the SonicWALL, so it would seem that the basic code is functioning properly.
I'm developing using .NET (VB.NET, specifically), and I've used this same code to successfully interact with several other API's from different providers. If anyone can offer some assistance, I'd greatly appreciate it. If providing some of the code would be helpful, I can do that as well.
Best Answers
-
Jaime SonicWall Employee
Hi @G_Hosa_Phat,
I tested this out and have a solution for you. Check out the items below and the correct JSON to use.
- The country name (not abbreviation) is expected. It will fail if the country name isn't in the list of expected names. The API is very similar to the CLI so sometimes the CLI can provide hints where the Swagger documentation does not.
- Don't include the elements that will be null. Notice the JSON below does not include the optional SAN, or the last two configurable elements of the CSR.
- The signature algorithm expects "md5", "sha-1", "sha-256", "sha-384", or "sha-512". The POST will fail if the signature algorithm is not one of the expected strings.
Please use the following JSON in your POST:
{ "certificates": { "generate_signing_request": [ { "alias": "test_csr", "distinguished_name": { "element1": { "country": "United States" }, "element2": { "state": "StateName" }, "element3": { "locality": "City Name" }, "element4": { "organization": "My Company Name" }, "element5": { "department": "Information Services" }, "element6": { "common_name": "test.mydomain.com" } }, "signature_algorithm": "sha-256", "key": { "type": "rsa", "size": "2048" }, "generate": true } ] } }
1 -
Jaime SonicWall Employee
Hi @G_Hosa_Phat,
The endpoint we've been working with is available on Gen7 only. On Gen6, I got it to work by sending a PUT to /certificates/export/signing-request/name/<NAME>/ftp/<FTPURL>. The same could be done with SCP. Take a look at the link at the bottom of this post.
Working example:
The URL needs to be encoded. ftp://cert:password@192.168.100.40/ will look like this: ftp%3A%2F%2Fcert%3Apassword%40192.168.100.40%2F
Please take a look at the link below for the appropriate Swagger documentation. I'm working with Engineering to make sure the 6.5.4.8 document is available.
Thanks.
Jaime
0
Answers
Thank you so much. I figured it was something like that, but this will honestly be my first time to really dig into the certificate process, so I wasn't sure where I was failing. I've got some "interesting" logic to build in my application in order to have it construct the JSON like that but, now that I have some "rules", I shouldn't have too much trouble getting it done.
BTW, does the CLI documentation spell these "rules" out better than that for the API? I have a feeling I'm going to run into things like this again at some point in my development process.
In my experience, the API follows the CLI command structure very closely, so you might find the CLI documentation and CLI help menus and auto-completion/tabbing to be helpful. I haven't actually looked at the CLI documentation for certificates, and it is my first time looking at generating a CSR using the API. Personally, when I run into an issue like that where I get syntax or schema validation errors, or "no command found" type of errors, I'll hop into an SSH or console session and follow the CLI command structure of what I'm working on. That's actually how I determined that the country needed to be "United States" and not "US".
Thank you again, @Jaime. Following the "rules" above, I was able to successfully generate the CSR from my application on the firewall. I logged into the UI and it shows up exactly as expected. Unfortunately, however, that was just the first step in the process, and I'm stuck again with another "Bad Request" to the API when I try to export the CSR to send on to the CA. As I stated before, I can GET the /address-objects/ipv4 just fine, but when I try to GET /export/certificates/signing-request/name/{NAME}, it keeps returning the 400 error.
https://192.168.168.168:4343/api/sonicos/export/certificates/signing-request/name/test_csr
I did as you suggested and logged into the firewall via SSH (using PuTTY) to see if I could figure out why:
This gives me an "Incomplete command" error. Reading the command line reference, the CLI seems to want a download protocol as well as a specific path/file name for where to save the CSR file. I tried a couple of times to get the CSR downloaded, but haven't been able to get it to complete the process through the CLI using SCP. Of course, that isn't really my main concern anyway since my goal is to do this through the API.
It did, however, give me a thought for why my previous attempts were failing. Thinking that the API might also be wanting to save the information to a file (instead of just passing the contents back), I went ahead and tried to add a parameter to the request for a local path on my computer:
https://192.168.168.168:4343/api/sonicos/export/certificates/signing-request/name/test_csr?path="C:\CSRTemp\test.csr"
That didn't work either (I kinda figured it wouldn't) and returned the same "Bad Request" error. If a path/file name is required, I'm guessing I'm going to need to format it a certain way, build it as a URI (e.g, "file://server/test.csr"), and/or perhaps even encode characters for the URL (like %22 for quotation marks, etc.). Again, though, the documentation on this API endpoint doesn't provide enough information for me to determine exactly how to set up the parameter name and value (if that is, in fact, the actual problem).
So, anyway, that's where this process stands. While I may be missing/forgetting something, there will be at least one more step (that I can think of) in the process before I'm done: importing the signed certificate from the CA. I may also want to build a method to export the certificate from the firewall as a "backup", but that shouldn't be 100% necessary. Based on the challenges I've encountered so far with this, I may have further questions down the line.
I just tested this on both Gen6 and Gen7. On the Gen6 6.5.4.8 firmware release, I am getting the same 400 Bad Request response with the "API endpoint is incomplete" message. I did some research and could not get it to work. On the Gen7 7.0.1 release, I am able to successfully export the CSR.
EDIT: I filed a report with Engineering regarding this API endpoint on 6.5.4.8.
For the step of importing the signed certificate, please take a look at this thread:
You, my friend, are a rock star! 🤩🤩🤩 Hopefully the Engineering team can help figure out the issue with the export or my work will have all been for naught. The only thing I could think to do otherwise would be to try to implement an entire SSH client in my application to use the CLI to do it, but putting all of that into my little .NET application seems a bit of overkill.
Either way, I suppose I'll work on the other elements to see if I can have them ready when Engineering comes back with the (working?) solution! Thank you yet again! 👊
Happy to help! Welcome to the SonicWall Community! 🎉
FANTASTIC! 🎉 Step 2 of the process is now working! 🎉
Interesting that it's using the PUT method instead of GET but, after a bit of trial-and-error, I have the API exporting the CSR to a file using the "new" endpoint. I'm not sure if I just overlooked those API endpoints, or what. I thought I had gone through the whole Swagger page before, but at least I can move on now.
Just for the sake of documenting the "process" in case someone else stumbles across this thread, here are the bits I had to work through:
So, now I get to move on to the next step of submitting the CSR to the CA and retrieving the signed certificate (not something the API can do 😜), then I can finally start playing around with the /certificates/import/signed-cert/name/{NAME} endpoint. I love it when a plan comes together!
Hello @G_Hosa_Phat,
You didn't overlook this endpoint. The root cause has been reported to Engineering. The 6.5.4.8 API documentation link is redirecting to the SonicOS 7.0.1 API documentation so we were looking at the wrong information. The link I provided in my previous post correctly loads the Gen6 API documentation.
You know where we can get DEMO scripts to upload the SSL Certificate to many SonicWalls to upload and activate it by CLI?