Ok, the spec mentions in one place "For all other control endpoints.....", so I guess it is possible to have control endpoint at non-0 index. This would be pretty bizarre, I have never seen this is done and I assume you will run int all sorts of issues with support for this. Pretty much everyone assumes EP0 and only EP0 to be a control endpoint.
Even looking at the libusb API, libusb_control_transfer(), which sends the SETUP-type transfer, does not take endpoint index, so you can only issue SETUP transactions to the ep0.
And I don't think there is a way to generate just an IN/OUT transfer to the control endpoint not as a part of the data stage of the SETUP transfer. All APIs infer the direction from the endpoint index, but the control endpoint uses the same index for both directions and the actual direction is derived from the SETUP packet.
So, it looks like even arbitrary exchange is not that easy. And this is why everyone (including DFU) uses SETUP transfers with vendor or class request types. You still get arbitrary payloads, just as a part of the data stage of the SETUP transfer. Plus you get a nice way to send additional request parameters in the fields of the setup packet.