xref: /src/contrib/libfido2/regress/mock.c (revision febb0da5bf4bc99828ebede7abcb039514ac367a)
1 /*
2  * Copyright (c) 2024 Yubico AB. All rights reserved.
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 
8 #undef NDEBUG
9 
10 #include <assert.h>
11 #include <string.h>
12 #include <time.h>
13 #include <stdint.h>
14 
15 #define _FIDO_INTERNAL
16 #include <fido.h>
17 
18 #include "extern.h"
19 #include "../fuzz/wiredata_fido2.h"
20 
21 #define REPORT_LEN	(64 + 1)
22 
23 static uint8_t	 ctap_nonce[8];
24 static uint8_t	*wiredata_ptr;
25 static size_t	 wiredata_len;
26 static int	 fake_dev_handle;
27 static int	 initialised;
28 static long	 interval_ms;
29 
30 #if defined(_MSC_VER)
31 static int
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)32 nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
33 {
34 	if (rmtp != NULL) {
35 		errno = EINVAL;
36 		return (-1);
37 	}
38 
39 	Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
40 
41 	return (0);
42 }
43 #endif
44 
45 static void *
dummy_open(const char * path)46 dummy_open(const char *path)
47 {
48 	(void)path;
49 
50 	return (&fake_dev_handle);
51 }
52 
53 static void
dummy_close(void * handle)54 dummy_close(void *handle)
55 {
56 	assert(handle == &fake_dev_handle);
57 }
58 
59 static int
dummy_read(void * handle,unsigned char * ptr,size_t len,int ms)60 dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
61 {
62 	struct timespec tv;
63 	size_t		n;
64 	long		d;
65 
66 	assert(handle == &fake_dev_handle);
67 	assert(ptr != NULL);
68 	assert(len == REPORT_LEN - 1);
69 
70 	if (wiredata_ptr == NULL)
71 		return (-1);
72 
73 	if (!initialised) {
74 		assert(wiredata_len >= REPORT_LEN - 1);
75 		memcpy(&wiredata_ptr[7], &ctap_nonce, sizeof(ctap_nonce));
76 		initialised = 1;
77 	}
78 
79 	if (ms >= 0 && ms < interval_ms)
80 		d = ms;
81 	else
82 		d = interval_ms;
83 
84 	if (d) {
85 		tv.tv_sec = d / 1000;
86 		tv.tv_nsec = (d % 1000) * 1000000;
87 		if (nanosleep(&tv, NULL) == -1)
88 			err(1, "nanosleep");
89 	}
90 
91 	if (d != interval_ms)
92 		return (-1); /* timeout */
93 
94 	if (wiredata_len < len)
95 		n = wiredata_len;
96 	else
97 		n = len;
98 
99 	memcpy(ptr, wiredata_ptr, n);
100 	wiredata_ptr += n;
101 	wiredata_len -= n;
102 
103 	return ((int)n);
104 }
105 
106 static int
dummy_write(void * handle,const unsigned char * ptr,size_t len)107 dummy_write(void *handle, const unsigned char *ptr, size_t len)
108 {
109 	struct timespec tv;
110 
111 	assert(handle == &fake_dev_handle);
112 	assert(ptr != NULL);
113 	assert(len == REPORT_LEN);
114 
115 	if (!initialised)
116 		memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce));
117 
118 	if (interval_ms) {
119 		tv.tv_sec = interval_ms / 1000;
120 		tv.tv_nsec = (interval_ms % 1000) * 1000000;
121 		if (nanosleep(&tv, NULL) == -1)
122 			err(1, "nanosleep");
123 	}
124 
125 	return ((int)len);
126 }
127 
128 uint8_t *
wiredata_setup(const uint8_t * data,size_t len)129 wiredata_setup(const uint8_t *data, size_t len)
130 {
131 	const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT };
132 
133 	assert(wiredata_ptr == NULL);
134 	assert(SIZE_MAX - len > sizeof(ctap_init_data));
135 	assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL);
136 
137 #if defined(_MSC_VER)
138 #pragma warning(push)
139 #pragma warning(disable:6386)
140 #endif
141 	memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data));
142 #if defined(_MSC_VER)
143 #pragma warning(pop)
144 #endif
145 
146 	if (len)
147 		memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len);
148 
149 	wiredata_len = sizeof(ctap_init_data) + len;
150 
151 	return (wiredata_ptr);
152 }
153 
154 void
wiredata_clear(uint8_t ** wiredata)155 wiredata_clear(uint8_t **wiredata)
156 {
157 	free(*wiredata);
158 	*wiredata = NULL;
159 	wiredata_ptr = NULL;
160 	wiredata_len = 0;
161 	initialised = 0;
162 }
163 
164 void
setup_dummy_io(fido_dev_t * dev)165 setup_dummy_io(fido_dev_t *dev)
166 {
167 	fido_dev_io_t io;
168 
169 	memset(&io, 0, sizeof(io));
170 	io.open = dummy_open;
171 	io.close = dummy_close;
172 	io.read = dummy_read;
173 	io.write = dummy_write;
174 
175 	assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
176 }
177 
178 void
set_read_interval(long ms)179 set_read_interval(long ms)
180 {
181 	interval_ms = ms;
182 }
183