1 /* $OpenBSD: urng.c,v 1.10 2020/05/29 04:42:25 deraadt 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/time.h> 35 #include <sys/timeout.h> 36 37 #include <dev/usb/usb.h> 38 #include <dev/usb/usbdi.h> 39 #include <dev/usb/usbdevs.h> 40 41 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) 42 43 #ifdef URNG_DEBUG 44 #define DPRINTF(x) printf x 45 #else 46 #define DPRINTF(x) 47 #endif 48 49 /* 50 * Define URNG_MEASURE_RATE to periodically log rate at which we provide 51 * random data to the kernel. 52 */ 53 #ifdef URNG_MEASURE_RATE 54 #define URNG_RATE_SECONDS 30 55 #endif 56 57 struct urng_chip { 58 int bufsiz; 59 int endpoint; 60 int ctl_iface_idx; 61 int msecs; 62 int read_timeout; 63 }; 64 65 struct urng_softc { 66 struct device sc_dev; 67 struct usbd_device *sc_udev; 68 struct usbd_pipe *sc_inpipe; 69 struct timeout sc_timeout; 70 struct usb_task sc_task; 71 struct usbd_xfer *sc_xfer; 72 struct urng_chip sc_chip; 73 int *sc_buf; 74 int sc_product; 75 #ifdef URNG_MEASURE_RATE 76 struct timeval sc_start; 77 struct timeval sc_cur; 78 int sc_counted_bytes; 79 u_char sc_first_run; 80 #endif 81 }; 82 83 int urng_match(struct device *, void *, void *); 84 void urng_attach(struct device *, struct device *, void *); 85 int urng_detach(struct device *, int); 86 void urng_task(void *); 87 void urng_timeout(void *); 88 89 struct cfdriver urng_cd = { 90 NULL, "urng", DV_DULL 91 }; 92 93 const struct cfattach urng_ca = { 94 sizeof(struct urng_softc), urng_match, urng_attach, urng_detach 95 }; 96 97 struct urng_type { 98 struct usb_devno urng_dev; 99 struct urng_chip urng_chip; 100 }; 101 102 static const struct urng_type urng_devs[] = { 103 { { USB_VENDOR_OPENMOKO2, USB_PRODUCT_OPENMOKO2_CHAOSKEY }, 104 {64, 5, 0, 100, 5000} }, 105 { { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, 106 {128, 1, 0, 100, 5000} }, 107 }; 108 #define urng_lookup(v, p) ((struct urng_type *)usb_lookup(urng_devs, v, p)) 109 110 int 111 urng_match(struct device *parent, void *match, void *aux) 112 { 113 struct usb_attach_arg *uaa = aux; 114 115 if (uaa->iface == NULL) 116 return (UMATCH_NONE); 117 118 if (urng_lookup(uaa->vendor, uaa->product) != NULL) 119 return (UMATCH_VENDOR_PRODUCT); 120 121 return (UMATCH_NONE); 122 } 123 124 void 125 urng_attach(struct device *parent, struct device *self, void *aux) 126 { 127 struct urng_softc *sc = (struct urng_softc *)self; 128 struct usb_attach_arg *uaa = aux; 129 usb_interface_descriptor_t *id; 130 usb_endpoint_descriptor_t *ed; 131 int ep_ibulk = -1; 132 usbd_status error; 133 int i, ep_addr; 134 135 sc->sc_udev = uaa->device; 136 sc->sc_chip = urng_lookup(uaa->vendor, uaa->product)->urng_chip; 137 sc->sc_product = uaa->product; 138 #ifdef URNG_MEASURE_RATE 139 sc->sc_first_run = 1; 140 #endif 141 142 DPRINTF(("%s: bufsiz: %d, endpoint: %d ctl iface: %d, msecs: %d, read_timeout: %d\n", 143 DEVNAME(sc), 144 sc->sc_chip.bufsiz, 145 sc->sc_chip.endpoint, 146 sc->sc_chip.ctl_iface_idx, 147 sc->sc_chip.msecs, 148 sc->sc_chip.read_timeout)); 149 150 /* Find the bulk endpoints. */ 151 id = usbd_get_interface_descriptor(uaa->iface); 152 for (i = 0; i < id->bNumEndpoints; i++) { 153 ed = usbd_interface2endpoint_descriptor(uaa->iface, i); 154 if (ed == NULL) { 155 printf("%s: failed to get endpoint %d descriptor\n", 156 DEVNAME(sc), i); 157 goto fail; 158 } 159 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 160 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 161 ep_addr = UE_GET_ADDR(ed->bEndpointAddress); 162 163 DPRINTF(("%s: bulk endpoint %d\n", 164 DEVNAME(sc), ep_addr)); 165 166 if (ep_addr == sc->sc_chip.endpoint) { 167 ep_ibulk = ed->bEndpointAddress; 168 break; 169 } 170 } 171 } 172 173 if (ep_ibulk == -1) { 174 printf("%s: missing bulk input endpoint\n", DEVNAME(sc)); 175 goto fail; 176 } 177 178 /* Open the pipes. */ 179 error = usbd_open_pipe(uaa->iface, ep_ibulk, USBD_EXCLUSIVE_USE, 180 &sc->sc_inpipe); 181 if (error) { 182 printf("%s: failed to open bulk-in pipe: %s\n", 183 DEVNAME(sc), usbd_errstr(error)); 184 goto fail; 185 } 186 187 /* Allocate the transfer buffers. */ 188 sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev); 189 if (sc->sc_xfer == NULL) { 190 printf("%s: could not alloc xfer\n", DEVNAME(sc)); 191 goto fail; 192 } 193 194 sc->sc_buf = usbd_alloc_buffer(sc->sc_xfer, sc->sc_chip.bufsiz); 195 if (sc->sc_buf == NULL) { 196 printf("%s: could not alloc %d-byte buffer\n", DEVNAME(sc), 197 sc->sc_chip.bufsiz); 198 goto fail; 199 } 200 201 /* And off we go! */ 202 usb_init_task(&sc->sc_task, urng_task, sc, USB_TASK_TYPE_GENERIC); 203 timeout_set(&sc->sc_timeout, urng_timeout, sc); 204 usb_add_task(sc->sc_udev, &sc->sc_task); 205 206 return; 207 208 fail: 209 usbd_deactivate(sc->sc_udev); 210 } 211 212 int 213 urng_detach(struct device *self, int flags) 214 { 215 struct urng_softc *sc = (struct urng_softc *)self; 216 217 usb_rem_task(sc->sc_udev, &sc->sc_task); 218 219 if (timeout_initialized(&sc->sc_timeout)) 220 timeout_del(&sc->sc_timeout); 221 222 if (sc->sc_xfer != NULL) { 223 usbd_free_xfer(sc->sc_xfer); 224 sc->sc_xfer = NULL; 225 } 226 227 if (sc->sc_inpipe != NULL) { 228 usbd_close_pipe(sc->sc_inpipe); 229 sc->sc_inpipe = NULL; 230 } 231 232 return (0); 233 } 234 235 236 void 237 urng_task(void *arg) 238 { 239 struct urng_softc *sc = (struct urng_softc *)arg; 240 usbd_status error; 241 u_int32_t len, i; 242 #ifdef URNG_MEASURE_RATE 243 time_t elapsed; 244 int rate; 245 #endif 246 usbd_setup_xfer(sc->sc_xfer, sc->sc_inpipe, NULL, sc->sc_buf, 247 sc->sc_chip.bufsiz, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, 248 sc->sc_chip.read_timeout, NULL); 249 250 error = usbd_transfer(sc->sc_xfer); 251 if (error) { 252 printf("%s: xfer failed: %s\n", DEVNAME(sc), 253 usbd_errstr(error)); 254 goto bail; 255 } 256 257 usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &len, NULL); 258 if (len < sizeof(int)) { 259 printf("%s: xfer too short (%u bytes) - dropping\n", 260 DEVNAME(sc), len); 261 goto bail; 262 } 263 264 #ifdef URNG_MEASURE_RATE 265 if (sc->sc_first_run) { 266 sc->sc_counted_bytes = 0; 267 getmicrotime(&(sc->sc_start)); 268 } 269 sc->sc_counted_bytes += len; 270 getmicrotime(&(sc->sc_cur)); 271 elapsed = sc->sc_cur.tv_sec - sc->sc_start.tv_sec; 272 if (elapsed >= URNG_RATE_SECONDS) { 273 rate = (8 * sc->sc_counted_bytes) / (elapsed * 1024); 274 printf("%s: transfer rate = %d kb/s\n", DEVNAME(sc), rate); 275 276 /* set up for next measurement */ 277 sc->sc_counted_bytes = 0; 278 getmicrotime(&(sc->sc_start)); 279 } 280 #endif 281 282 len /= sizeof(int); 283 for (i = 0; i < len; i++) { 284 enqueue_randomness(sc->sc_buf[i]); 285 } 286 bail: 287 #ifdef URNG_MEASURE_RATE 288 if (sc->sc_first_run) { 289 sc->sc_first_run = 0; 290 } 291 #endif 292 293 timeout_add_msec(&sc->sc_timeout, sc->sc_chip.msecs); 294 } 295 296 void 297 urng_timeout(void *arg) 298 { 299 struct urng_softc *sc = arg; 300 301 usb_add_task(sc->sc_udev, &sc->sc_task); 302 } 303