xref: /freebsd/contrib/libfido2/CMakeLists.txt (revision 9768746b)
1# Copyright (c) 2018 Yubico AB. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file.
4
5# detect AppleClang; needs to come before project()
6cmake_policy(SET CMP0025 NEW)
7
8project(libfido2 C)
9cmake_minimum_required(VERSION 3.0)
10# Set PIE flags for POSITION_INDEPENDENT_CODE targets, added in CMake 3.14.
11if(POLICY CMP0083)
12  cmake_policy(SET CMP0083 NEW)
13endif()
14
15include(CheckCCompilerFlag)
16include(CheckFunctionExists)
17include(CheckLibraryExists)
18include(CheckSymbolExists)
19include(CheckIncludeFiles)
20include(CheckTypeSize)
21include(GNUInstallDirs)
22include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED)
23if(CHECK_PIE_SUPPORTED)
24  check_pie_supported(LANGUAGES C)
25endif()
26
27set(CMAKE_POSITION_INDEPENDENT_CODE ON)
28set(CMAKE_COLOR_MAKEFILE OFF)
29set(CMAKE_VERBOSE_MAKEFILE ON)
30set(FIDO_MAJOR "1")
31set(FIDO_MINOR "8")
32set(FIDO_PATCH "0")
33set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
34
35option(BUILD_EXAMPLES    "Build example programs"                  ON)
36option(BUILD_MANPAGES    "Build man pages"                         ON)
37option(BUILD_SHARED_LIBS "Build the shared library"                ON)
38option(BUILD_STATIC_LIBS "Build the static library"                ON)
39option(BUILD_TOOLS       "Build tool programs"                     ON)
40option(FUZZ              "Enable fuzzing instrumentation"          OFF)
41option(LIBFUZZER         "Build libfuzzer harnesses"               OFF)
42option(USE_HIDAPI        "Use hidapi as the HID backend"           OFF)
43option(USE_WINHELLO      "Abstract Windows Hello as a FIDO device" OFF)
44option(NFC_LINUX         "Experimental NFC support on Linux"       OFF)
45
46add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR})
47add_definitions(-D_FIDO_MINOR=${FIDO_MINOR})
48add_definitions(-D_FIDO_PATCH=${FIDO_PATCH})
49
50if(CYGWIN OR MSYS)
51	set(WIN32 1)
52	add_definitions(-DWINVER=0x0a00)
53endif()
54
55if(WIN32)
56	add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600)
57endif()
58
59if(APPLE)
60	set(CMAKE_INSTALL_NAME_DIR
61	    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
62endif()
63
64if(NOT MSVC)
65	set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_POSIX_C_SOURCE=200809L")
66	set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_BSD_SOURCE")
67	if(APPLE)
68		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE")
69		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1")
70	elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
71		set(NFC_LINUX OFF)
72		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE")
73		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE")
74	elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
75		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1")
76	endif()
77	set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99")
78	set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}")
79endif()
80
81check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
82check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
83
84check_include_files(cbor.h HAVE_CBOR_H)
85check_include_files(endian.h HAVE_ENDIAN_H)
86check_include_files(err.h HAVE_ERR_H)
87check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H)
88check_include_files(signal.h HAVE_SIGNAL_H)
89check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
90check_include_files(unistd.h HAVE_UNISTD_H)
91check_include_files("windows.h;webauthn.h" HAVE_WEBAUTHN_H)
92
93check_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF)
94check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)
95check_symbol_exists(explicit_bzero string.h HAVE_EXPLICIT_BZERO)
96check_symbol_exists(freezero stdlib.h HAVE_FREEZERO)
97check_symbol_exists(getline stdio.h HAVE_GETLINE)
98check_symbol_exists(getopt unistd.h HAVE_GETOPT)
99check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
100check_symbol_exists(getrandom sys/random.h HAVE_GETRANDOM)
101check_symbol_exists(memset_s string.h HAVE_MEMSET_S)
102check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE)
103check_symbol_exists(recallocarray stdlib.h HAVE_RECALLOCARRAY)
104check_symbol_exists(sigaction signal.h HAVE_SIGACTION)
105check_symbol_exists(strlcat string.h HAVE_STRLCAT)
106check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
107check_symbol_exists(sysconf unistd.h HAVE_SYSCONF)
108check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
109check_symbol_exists(timingsafe_bcmp string.h HAVE_TIMINGSAFE_BCMP)
110
111set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
112check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T)
113set(CMAKE_EXTRA_INCLUDE_FILES)
114
115set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
116try_compile(HAVE_POSIX_IOCTL
117    "${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o"
118    "${CMAKE_CURRENT_SOURCE_DIR}/openbsd-compat/posix_ioctl_check.c"
119    COMPILE_DEFINITIONS "-Werror -Woverflow -Wsign-conversion")
120
121list(APPEND CHECK_VARIABLES
122	HAVE_ARC4RANDOM_BUF
123	HAVE_CBOR_H
124	HAVE_CLOCK_GETTIME
125	HAVE_ENDIAN_H
126	HAVE_ERR_H
127	HAVE_FREEZERO
128	HAVE_GETLINE
129	HAVE_GETOPT
130	HAVE_GETPAGESIZE
131	HAVE_GETRANDOM
132	HAVE_MEMSET_S
133	HAVE_OPENSSLV_H
134	HAVE_POSIX_IOCTL
135	HAVE_READPASSPHRASE
136	HAVE_RECALLOCARRAY
137	HAVE_SIGACTION
138	HAVE_SIGNAL_H
139	HAVE_STRLCAT
140	HAVE_STRLCPY
141	HAVE_SYSCONF
142	HAVE_SYS_RANDOM_H
143	HAVE_TIMESPECSUB
144	HAVE_TIMINGSAFE_BCMP
145	HAVE_UNISTD_H
146	HAVE_WEBAUTHN_H
147)
148
149foreach(v ${CHECK_VARIABLES})
150	if (${v})
151		add_definitions(-D${v})
152	endif()
153endforeach()
154
155if(HAVE_EXPLICIT_BZERO AND NOT LIBFUZZER)
156	add_definitions(-DHAVE_EXPLICIT_BZERO)
157endif()
158
159if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL ""))
160	add_definitions(-DSIGNAL_EXAMPLE)
161endif()
162
163if(UNIX)
164	add_definitions(-DHAVE_DEV_URANDOM)
165endif()
166
167if(MSVC)
168	if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR
169	   (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR
170	   (NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS))
171		message(FATAL_ERROR "please provide definitions for "
172		   "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when building "
173		    "under msvc")
174	endif()
175	set(CBOR_LIBRARIES cbor)
176	set(ZLIB_LIBRARIES zlib)
177	set(CRYPTO_LIBRARIES crypto-46)
178	set(MSVC_DISABLED_WARNINGS_LIST
179		"C4200" # nonstandard extension used: zero-sized array in
180			# struct/union;
181		"C4204" # nonstandard extension used: non-constant aggregate
182			# initializer;
183		"C4706" # assignment within conditional expression;
184		"C4996" # The POSIX name for this item is deprecated. Instead,
185			# use the ISO C and C++ conformant name;
186		"C6287" # redundant code: the left and right subexpressions are identical
187		)
188	# The construction in the following 3 lines was taken from LibreSSL's
189	# CMakeLists.txt.
190	string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
191	    ${MSVC_DISABLED_WARNINGS_LIST})
192	string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
193	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}")
194	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7 /guard:cf /sdl /RTCcsu")
195	set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl")
196	if (HAVE_WEBAUTHN_H)
197		add_definitions(-DUSE_WINHELLO)
198		set(USE_WINHELLO ON)
199	endif()
200else()
201	include(FindPkgConfig)
202	pkg_search_module(CBOR libcbor)
203	pkg_search_module(CRYPTO libcrypto)
204	pkg_search_module(ZLIB zlib)
205
206	if(NOT CBOR_FOUND AND NOT HAVE_CBOR_H)
207		message(FATAL_ERROR "could not find libcbor")
208	endif()
209	if(NOT CRYPTO_FOUND AND NOT HAVE_OPENSSLV_H)
210		message(FATAL_ERROR "could not find libcrypto")
211	endif()
212	if(NOT ZLIB_FOUND)
213		message(FATAL_ERROR "could not find zlib")
214	endif()
215
216	set(CBOR_LIBRARIES "cbor")
217	set(CRYPTO_LIBRARIES "crypto")
218
219	if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
220		pkg_search_module(UDEV libudev REQUIRED)
221		set(UDEV_NAME "udev")
222		# If using hidapi, use hidapi-hidraw.
223		set(HIDAPI_SUFFIX -hidraw)
224		if(NOT HAVE_CLOCK_GETTIME)
225			# Look for clock_gettime in librt.
226			check_library_exists(rt clock_gettime "time.h"
227			    HAVE_CLOCK_GETTIME)
228			if (HAVE_CLOCK_GETTIME)
229				add_definitions(-DHAVE_CLOCK_GETTIME)
230				set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
231			endif()
232		endif()
233	endif()
234
235	if(MINGW)
236		# MinGW is stuck with a flavour of C89.
237		add_definitions(-DFIDO_NO_DIAGNOSTIC)
238		add_definitions(-DWC_ERR_INVALID_CHARS=0x80)
239		add_compile_options(-Wno-unused-parameter)
240	endif()
241
242	if(USE_HIDAPI)
243		add_definitions(-DUSE_HIDAPI)
244		pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
245		set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
246	endif()
247
248	if(FUZZ)
249		set(NFC_LINUX ON)
250	endif()
251
252	if(NFC_LINUX)
253		add_definitions(-DNFC_LINUX)
254	endif()
255
256	add_compile_options(-Wall)
257	add_compile_options(-Wextra)
258	add_compile_options(-Werror)
259	add_compile_options(-Wshadow)
260	add_compile_options(-Wcast-qual)
261	add_compile_options(-Wwrite-strings)
262	add_compile_options(-Wmissing-prototypes)
263	add_compile_options(-Wbad-function-cast)
264	add_compile_options(-pedantic)
265	add_compile_options(-pedantic-errors)
266
267	if(HAVE_SHORTEN_64_TO_32)
268		add_compile_options(-Wshorten-64-to-32)
269	endif()
270	if(HAVE_STACK_PROTECTOR_ALL)
271		add_compile_options(-fstack-protector-all)
272	endif()
273
274	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2")
275	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer")
276	set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2")
277
278	if(FUZZ)
279		add_definitions(-DFIDO_FUZZ)
280	endif()
281	if(LIBFUZZER)
282		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
283	endif()
284endif()
285
286# Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
287if(CMAKE_COMPILER_IS_GNUCC)
288	add_compile_options(-Wno-unused-result)
289endif()
290
291# Decide which keyword to use for thread-local storage.
292if(CMAKE_COMPILER_IS_GNUCC OR
293   CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
294   CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
295	set(TLS "__thread")
296elseif(WIN32)
297	set(TLS "__declspec(thread)")
298endif()
299add_definitions(-DTLS=${TLS})
300
301# export list
302if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
303   CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
304	# clang + lld
305	string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
306	    " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm")
307elseif(NOT MSVC)
308	# clang/gcc + gnu ld
309	if(FUZZ)
310		string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
311                    " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/fuzz/export.gnu")
312	else()
313		string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
314                    " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu")
315	endif()
316	if(NOT WIN32)
317		string(CONCAT CMAKE_SHARED_LINKER_FLAGS
318		    ${CMAKE_SHARED_LINKER_FLAGS}
319		    " -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
320		string(CONCAT CMAKE_EXE_LINKER_FLAGS
321		    ${CMAKE_EXE_LINKER_FLAGS}
322		    " -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
323		if(FUZZ)
324			file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS)
325			foreach(s ${WRAPPED_SYMBOLS})
326				string(CONCAT CMAKE_SHARED_LINKER_FLAGS
327				    ${CMAKE_SHARED_LINKER_FLAGS}
328				    " -Wl,--wrap=${s}")
329			endforeach()
330		endif()
331	endif()
332else()
333	string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
334	    " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
335endif()
336
337include_directories(${CMAKE_SOURCE_DIR}/src)
338include_directories(${CBOR_INCLUDE_DIRS})
339include_directories(${CRYPTO_INCLUDE_DIRS})
340include_directories(${HIDAPI_INCLUDE_DIRS})
341include_directories(${UDEV_INCLUDE_DIRS})
342include_directories(${ZLIB_INCLUDE_DIRS})
343
344link_directories(${CBOR_LIBRARY_DIRS})
345link_directories(${CRYPTO_LIBRARY_DIRS})
346link_directories(${HIDAPI_LIBRARY_DIRS})
347link_directories(${UDEV_LIBRARY_DIRS})
348link_directories(${ZLIB_LIBRARY_DIRS})
349
350message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}")
351message(STATUS "BUILD_EXAMPLES: ${BUILD_EXAMPLES}")
352message(STATUS "BUILD_MANPAGES: ${BUILD_MANPAGES}")
353message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
354message(STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}")
355message(STATUS "BUILD_TOOLS: ${BUILD_TOOLS}")
356message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
357message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
358message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
359message(STATUS "CBOR_VERSION: ${CBOR_VERSION}")
360message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
361message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
362message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
363message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
364message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
365message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
366message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
367message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}")
368message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
369message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
370message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
371message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}")
372message(STATUS "FIDO_VERSION: ${FIDO_VERSION}")
373message(STATUS "FUZZ: ${FUZZ}")
374message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")
375message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
376message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}")
377message(STATUS "ZLIB_VERSION: ${ZLIB_VERSION}")
378if(USE_HIDAPI)
379	message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}")
380	message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}")
381	message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
382	message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}")
383endif()
384message(STATUS "LIBFUZZER: ${LIBFUZZER}")
385message(STATUS "TLS: ${TLS}")
386message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
387message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}")
388message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
389message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
390message(STATUS "UDEV_VERSION: ${UDEV_VERSION}")
391message(STATUS "USE_HIDAPI: ${USE_HIDAPI}")
392message(STATUS "USE_WINHELLO: ${USE_WINHELLO}")
393message(STATUS "NFC_LINUX: ${NFC_LINUX}")
394
395subdirs(src)
396if(BUILD_EXAMPLES)
397	subdirs(examples)
398endif()
399if(BUILD_TOOLS)
400	subdirs(tools)
401endif()
402if(BUILD_MANPAGES)
403	subdirs(man)
404endif()
405
406if(NOT WIN32)
407	if(CMAKE_BUILD_TYPE STREQUAL "Debug")
408		if(NOT LIBFUZZER AND NOT FUZZ)
409			subdirs(regress)
410		endif()
411	endif()
412	if(FUZZ)
413		subdirs(fuzz)
414	endif()
415	if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
416		subdirs(udev)
417	endif()
418endif()
419