As a followup, I got dfu-util to spit out more useful information using the verbose option. There's a bunch of output but the part where things break is here:
Deducing device DFU version from functional descriptor length
[ 0.006410] [00000307] libusb: debug [libusb_get_device_descriptor]
[ 0.006413] [00000307] libusb: debug [libusb_get_config_descriptor] index 0
Opening DFU capable USB device...
[ 0.006420] [00000307] libusb: debug [libusb_open] open 20.25
[ 0.006492] [00000307] libusb: debug [darwin_open] device open for access
ID 1c11:b007
Run-time device DFU version 0101
Claiming USB DFU Interface...
[ 0.006505] [00000307] libusb: debug [libusb_claim_interface] interface 0
[ 0.006861] [00000307] libusb: debug [get_endpoints] building table of endpoints.
[ 0.006893] [00000307] libusb: debug [darwin_claim_interface] interface opened
Setting Alternate Setting #0 ...
[ 0.006904] [00000307] libusb: debug [libusb_set_interface_alt_setting] interface 0 altsetting 0
[ 0.007177] [00000307] libusb: debug [get_endpoints] building table of endpoints.
Determining device status: [ 0.007193] [00000307] libusb: debug [libusb_alloc_transfer] transfer 0x7fea66c077e8
[ 0.007197] [00000307] libusb: debug [libusb_submit_transfer] transfer 0x7fea66c077e8
[ 0.007224] [00000307] libusb: debug [libusb_get_next_timeout] no URB with timeout or all handled by OS; no timeout!
[ 0.007229] [00000307] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 0.007232] [00000307] libusb: debug [handle_events] poll() 1 fds with timeout in 60000ms
[ 0.007340] [00001507] libusb: debug [darwin_async_io_callback] an async io operation has completed
[ 0.007358] [00000307] libusb: debug [handle_events] poll() returned 1
[ 0.007363] [00000307] libusb: debug [handle_events] caught a fish on the event pipe
[ 0.007365] [00000307] libusb: debug [darwin_handle_transfer_completion] handling control completion with kernel status 0
[ 0.007369] [00000307] libusb: debug [usbi_handle_transfer_completion] transfer 0x7fea66c077e8 has callback 0x10d88f130
[ 0.007372] [00000307] libusb: debug [sync_transfer_cb] actual_length=6
[ 0.007376] [00000307] libusb: debug [libusb_free_transfer] transfer 0x7fea66c077e8
state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0101
Device returned transfer size 1024
Copying data from PC to DFU device
Download [ ] 0% 0 bytes[ 1.012245] [00000307] libusb: debug [libusb_alloc_transfer] transfer 0x7fea66e023f8
[ 1.012254] [00000307] libusb: debug [libusb_submit_transfer] transfer 0x7fea66e023f8
[ 1.012362] [00000307] libusb: debug [libusb_get_next_timeout] no URB with timeout or all handled by OS; no timeout!
[ 1.012374] [00000307] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 1.012379] [00000307] libusb: debug [handle_events] poll() 1 fds with timeout in 60000ms
[ 1.116848] [00001507] libusb: debug [darwin_async_io_callback] an async io operation has completed
[ 1.116902] [00000307] libusb: debug [handle_events] poll() returned 1
[ 1.116920] [00000307] libusb: debug [handle_events] caught a fish on the event pipe
[ 1.116926] [00000307] libusb: debug [darwin_handle_transfer_completion] handling control completion with kernel status -536870163
[ 1.116932] [00000307] libusb: warning [darwin_transfer_status] transfer error: device not responding (value = 0xe00002ed)
[ 1.116938] [00000307] libusb: debug [usbi_handle_transfer_completion] transfer 0x7fea66e023f8 has callback 0x10d88f130
[ 1.116944] [00000307] libusb: debug [sync_transfer_cb] actual_length=0
[ 1.116953] [00000307] libusb: debug [libusb_free_transfer] transfer 0x7fea66e023f8
dfu-util: Error during download
[ 1.116998] [00000307] libusb: debug [libusb_close]
[ 1.117006] [00000307] libusb: debug [libusb_release_interface] interface 0
[ 1.117126] [00001507] libusb: debug [darwin_devices_detached] notifying context 0x7fea66d01610 of device disconnect
[ 1.117765] [00000307] libusb: debug [libusb_exit]
[ 1.117787] [00000307] libusb: debug [libusb_exit] destroying default context