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