1 /* $OpenBSD: urng.c,v 1.11 2024/05/23 03:21:09 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Jasper Lievisse Adriaanse <jasper@openbsd.org> 5 * Copyright (c) 2017 Aaron Bieber <abieber@openbsd.org> 6 * Copyright (C) 2015 Sean Levy <attila@stalphonsos.com> 7 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> 8 * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> 9 * 10 * Permission to use, copy, modify, and distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23 /* 24 * Universal TRNG driver for a collection of TRNG devices: 25 * - ChaosKey TRNG 26 * http://altusmetrum.org/ChaosKey/ 27 * - Alea II TRNG. Produces 100kbit/sec of entropy by black magic 28 * http://www.araneus.fi/products/alea2/en/ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/device.h> 34 #include <sys/timeout.h> 35 36 #include <dev/usb/usb.h> 37 #include <dev/usb/usbdi.h> 38 #include <dev/usb/usbdevs.h> 39 40 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) 41 42 #ifdef URNG_DEBUG 43 #define DPRINTF(x) printf x 44 #else 45 #define DPRINTF(x) 46 #endif 47 48 /* 49 * Define URNG_MEASURE_RATE to periodically log rate at which we provide 50 * random data to the kernel. 51 */ 52 #ifdef URNG_MEASURE_RATE 53 #define URNG_RATE_SECONDS 30 54 #endif 55 56 struct urng_chip { 57 int bufsiz; 58 int endpoint; 59 int ctl_iface_idx; 60 int msecs; 61 int read_timeout; 62 }; 63 64 struct urng_softc { 65 struct device sc_dev; 66 struct usbd_device *sc_udev; 67 struct usbd_pipe *sc_inpipe; 68 struct timeout sc_timeout; 69 struct usb_task sc_task; 70 struct usbd_xfer *sc_xfer; 71 struct urng_chip sc_chip; 72 int *sc_buf; 73 int sc_product; 74 #ifdef URNG_MEASURE_RATE 75 struct timeval sc_start; 76 struct timeval sc_cur; 77 int sc_counted_bytes; 78 u_char sc_first_run; 79 #endif 80 }; 81 82 int urng_match(struct device *, void *, void *); 83 void urng_attach(struct device *, struct device *, void *); 84 int urng_detach(struct device *, int); 85 void urng_task(void *); 86 void urng_timeout(void *); 87 88 struct cfdriver urng_cd = { 89 NULL, "urng", DV_DULL 90 }; 91 92 const struct cfattach urng_ca = { 93 sizeof(struct urng_softc), urng_match, urng_attach, urng_detach 94 }; 95 96 struct urng_type { 97 struct usb_devno urng_dev; 98 struct urng_chip urng_chip; 99 }; 100 101 static const struct urng_type urng_devs[] = { 102 { { USB_VENDOR_OPENMOKO2, USB_PRODUCT_OPENMOKO2_CHAOSKEY }, 103 {64, 5, 0, 100, 5000} }, 104 { { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, 105 {128, 1, 0, 100, 5000} }, 106 }; 107 #define urng_lookup(v, p) ((struct urng_type *)usb_lookup(urng_devs, v, p)) 108 109 int 110 urng_match(struct device *parent, void *match, void *aux) 111 { 112 struct usb_attach_arg *uaa = aux; 113 114 if (uaa->iface == NULL) 115 return (UMATCH_NONE); 116 117 if (urng_lookup(uaa->vendor, uaa->product) != NULL) 118 return (UMATCH_VENDOR_PRODUCT); 119 120 return (UMATCH_NONE); 121 } 122 123 void 124 urng_attach(struct device *parent, struct device *self, void *aux) 125 { 126 struct urng_softc *sc = (struct urng_softc *)self; 127 struct usb_attach_arg *uaa = aux; 128 usb_interface_descriptor_t *id; 129 usb_endpoint_descriptor_t *ed; 130 int ep_ibulk = -1; 131 usbd_status error; 132 int i, ep_addr; 133 134 sc->sc_udev = uaa->device; 135 sc->sc_chip = urng_lookup(uaa->vendor, uaa->product)->urng_chip; 136 sc->sc_product = uaa->product; 137 #ifdef URNG_MEASURE_RATE 138 sc->sc_first_run = 1; 139 #endif 140 141 DPRINTF(("%s: bufsiz: %d, endpoint: %d ctl iface: %d, msecs: %d, read_timeout: %d\n", 142 DEVNAME(sc), 143 sc->sc_chip.bufsiz, 144 sc->sc_chip.endpoint, 145 sc->sc_chip.ctl_iface_idx, 146 sc->sc_chip.msecs, 147 sc->sc_chip.read_timeout)); 148 149 /* Find the bulk endpoints. */ 150 id = usbd_get_interface_descriptor(uaa->iface); 151 for (i = 0; i < id->bNumEndpoints; i++) { 152 ed = usbd_interface2endpoint_descriptor(uaa->iface, i); 153 if (ed == NULL) { 154 printf("%s: failed to get endpoint %d descriptor\n", 155 DEVNAME(sc), i); 156 goto fail; 157 } 158 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 159 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 160 ep_addr = UE_GET_ADDR(ed->bEndpointAddress); 161 162 DPRINTF(("%s: bulk endpoint %d\n", 163 DEVNAME(sc), ep_addr)); 164 165 if (ep_addr == sc->sc_chip.endpoint) { 166 ep_ibulk = ed->bEndpointAddress; 167 break; 168 } 169 } 170 } 171 172 if (ep_ibulk == -1) { 173 printf("%s: missing bulk input endpoint\n", DEVNAME(sc)); 174 goto fail; 175 } 176 177 /* Open the pipes. */ 178 error = usbd_open_pipe(uaa->iface, ep_ibulk, USBD_EXCLUSIVE_USE, 179 &sc->sc_inpipe); 180 if (error) { 181 printf("%s: failed to open bulk-in pipe: %s\n", 182 DEVNAME(sc), usbd_errstr(error)); 183 goto fail; 184 } 185 186 /* Allocate the transfer buffers. */ 187 sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev); 188 if (sc->sc_xfer == NULL) { 189 printf("%s: could not alloc xfer\n", DEVNAME(sc)); 190 goto fail; 191 } 192 193 sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, sc->sc_chip.bufsiz); 194 if (sc->sc_buf == NULL) { 195 printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc), 196 sc->sc_chip.bufsiz); 197 goto fail; 198 } 199 200 /* And off we go! */ 201 usb_init_task(&sc->sc_task, urng_task, sc, USB_TASK_TYPE_GENERIC); 202 timeout_set(&sc->sc_timeout, urng_timeout, sc); 203 usb_add_task(sc->sc_udev, &sc->sc_task); 204 205 return; 206 207 fail: 208 usbd_deactivate(sc->sc_udev); 209 } 210 211 int 212 urng_detach(struct device *self, int flags) 213 { 214 struct urng_softc *sc = (struct urng_softc *)self; 215 216 usb_rem_task(sc->sc_udev, &sc->sc_task); 217 218 if (timeout_initialized(&sc->sc_timeout)) 219 timeout_del(&sc->sc_timeout); 220 221 if (sc->sc_xfer != NULL) { 222 usbd_free_xfer(sc->sc_xfer); 223 sc->sc_xfer = NULL; 224 } 225 226 if (sc->sc_inpipe != NULL) { 227 usbd_close_pipe(sc->sc_inpipe); 228 sc->sc_inpipe = NULL; 229 } 230 231 return (0); 232 } 233 234 235 void 236 urng_task(void *arg) 237 { 238 struct urng_softc *sc = (struct urng_softc *)arg; 239 usbd_status error; 240 u_int32_t len, i; 241 #ifdef URNG_MEASURE_RATE 242 time_t elapsed; 243 int rate; 244 #endif 245 usbd_setup_xfer(sc->sc_xfer, sc->sc_inpipe, NULL, sc->sc_buf, 246 sc->sc_chip.bufsiz, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, 247 sc->sc_chip.read_timeout, NULL); 248 249 error = usbd_transfer(sc->sc_xfer); 250 if (error) { 251 printf("%s: xfer failed: %s\n", DEVNAME(sc), 252 usbd_errstr(error)); 253 goto bail; 254 } 255 256 usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL); 257 if (len < sizeof(int)) { 258 printf("%s: xfer too short (%u bytes) - dropping\n", 259 DEVNAME(sc), len); 260 goto bail; 261 } 262 263 #ifdef URNG_MEASURE_RATE 264 if (sc->sc_first_run) { 265 sc->sc_counted_bytes = 0; 266 getmicrotime(&(sc->sc_start)); 267 } 268 sc->sc_counted_bytes += len; 269 getmicrotime(&(sc->sc_cur)); 270 elapsed = sc->sc_cur.tv_sec - sc->sc_start.tv_sec; 271 if (elapsed >= URNG_RATE_SECONDS) { 272 rate = (8 * sc->sc_counted_bytes) / (elapsed * 1024); 273 printf("%s: transfer rate = %d kb/s\n", DEVNAME(sc), rate); 274 275 /* set up for next measurement */ 276 sc->sc_counted_bytes = 0; 277 getmicrotime(&(sc->sc_start)); 278 } 279 #endif 280 281 len /= sizeof(int); 282 for (i = 0; i < len; i++) { 283 enqueue_randomness(sc->sc_buf[i]); 284 } 285 bail: 286 #ifdef URNG_MEASURE_RATE 287 if (sc->sc_first_run) { 288 sc->sc_first_run = 0; 289 } 290 #endif 291 292 timeout_add_msec(&sc->sc_timeout, sc->sc_chip.msecs); 293 } 294 295 void 296 urng_timeout(void *arg) 297 { 298 struct urng_softc *sc = arg; 299 300 usb_add_task(sc->sc_udev, &sc->sc_task); 301 } 302