xref: /freebsd/contrib/libfido2/CMakeLists.txt (revision a18b956b73cee784e5c422d20fd0e4dabebd7eee)
1# Copyright (c) 2018-2021 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 "10")
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" ON)
44option(NFC_LINUX         "Enable NFC support on Linux"             ON)
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 OR MINGW)
51	set(WIN32 1)
52endif()
53
54if(WIN32)
55	add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600)
56endif()
57
58if(APPLE)
59	set(CMAKE_INSTALL_NAME_DIR
60	    "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
61endif()
62
63if(NOT MSVC)
64	set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_POSIX_C_SOURCE=200809L")
65	set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_BSD_SOURCE")
66	if(APPLE)
67		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE")
68		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1")
69	elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
70		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE")
71		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE")
72	elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
73	    CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
74		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1")
75	elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
76		set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_NETBSD_SOURCE")
77	endif()
78	set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99")
79	set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}")
80endif()
81
82check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
83check_c_compiler_flag("-Werror -fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
84
85check_include_files(cbor.h HAVE_CBOR_H)
86check_include_files(endian.h HAVE_ENDIAN_H)
87check_include_files(err.h HAVE_ERR_H)
88check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H)
89check_include_files(signal.h HAVE_SIGNAL_H)
90check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
91check_include_files(unistd.h HAVE_UNISTD_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(strlcat string.h HAVE_STRLCAT)
105check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
106check_symbol_exists(strsep string.h HAVE_STRSEP)
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_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
112try_compile(HAVE_POSIX_IOCTL
113    "${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o"
114    "${CMAKE_CURRENT_SOURCE_DIR}/openbsd-compat/posix_ioctl_check.c"
115    COMPILE_DEFINITIONS "-Werror -Woverflow -Wsign-conversion")
116
117list(APPEND CHECK_VARIABLES
118	HAVE_ARC4RANDOM_BUF
119	HAVE_CBOR_H
120	HAVE_CLOCK_GETTIME
121	HAVE_ENDIAN_H
122	HAVE_ERR_H
123	HAVE_FREEZERO
124	HAVE_GETLINE
125	HAVE_GETOPT
126	HAVE_GETPAGESIZE
127	HAVE_GETRANDOM
128	HAVE_MEMSET_S
129	HAVE_OPENSSLV_H
130	HAVE_POSIX_IOCTL
131	HAVE_READPASSPHRASE
132	HAVE_RECALLOCARRAY
133	HAVE_SIGNAL_H
134	HAVE_STRLCAT
135	HAVE_STRLCPY
136	HAVE_STRSEP
137	HAVE_SYSCONF
138	HAVE_SYS_RANDOM_H
139	HAVE_TIMESPECSUB
140	HAVE_TIMINGSAFE_BCMP
141	HAVE_UNISTD_H
142)
143
144foreach(v ${CHECK_VARIABLES})
145	if (${v})
146		add_definitions(-D${v})
147	endif()
148endforeach()
149
150if(HAVE_EXPLICIT_BZERO AND NOT LIBFUZZER)
151	add_definitions(-DHAVE_EXPLICIT_BZERO)
152endif()
153
154if(UNIX)
155	add_definitions(-DHAVE_DEV_URANDOM)
156endif()
157
158if(MSVC)
159	if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR
160	   (NOT CBOR_BIN_DIRS) OR (NOT CRYPTO_INCLUDE_DIRS) OR
161	   (NOT CRYPTO_LIBRARY_DIRS) OR (NOT CRYPTO_BIN_DIRS) OR
162	   (NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS) OR
163	   (NOT ZLIB_BIN_DIRS))
164		message(FATAL_ERROR "please define "
165		   "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY,BIN}_DIRS when "
166		   "building under msvc")
167	endif()
168	set(CBOR_LIBRARIES cbor)
169	set(ZLIB_LIBRARIES zlib)
170	set(CRYPTO_LIBRARIES crypto-47)
171	set(MSVC_DISABLED_WARNINGS_LIST
172		"C4152" # nonstandard extension used: function/data pointer
173			# conversion in expression;
174		"C4200" # nonstandard extension used: zero-sized array in
175			# struct/union;
176		"C4201" # nonstandard extension used: nameless struct/union;
177		"C4204" # nonstandard extension used: non-constant aggregate
178			# initializer;
179		"C4706" # assignment within conditional expression;
180		"C4996" # The POSIX name for this item is deprecated. Instead,
181			# use the ISO C and C++ conformant name;
182		"C6287" # redundant code: the left and right subexpressions are identical
183		)
184	# The construction in the following 3 lines was taken from LibreSSL's
185	# CMakeLists.txt.
186	string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
187	    ${MSVC_DISABLED_WARNINGS_LIST})
188	string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
189	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}")
190	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Z7 /guard:cf /sdl /RTCcsu")
191	set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl")
192	if(USE_WINHELLO)
193		add_definitions(-DUSE_WINHELLO)
194	endif()
195	set(NFC_LINUX OFF)
196else()
197	include(FindPkgConfig)
198	pkg_search_module(CBOR libcbor)
199	pkg_search_module(CRYPTO libcrypto)
200	pkg_search_module(ZLIB zlib)
201
202	if(NOT CBOR_FOUND AND NOT HAVE_CBOR_H)
203		message(FATAL_ERROR "could not find libcbor")
204	endif()
205	if(NOT CRYPTO_FOUND AND NOT HAVE_OPENSSLV_H)
206		message(FATAL_ERROR "could not find libcrypto")
207	endif()
208	if(NOT ZLIB_FOUND)
209		message(FATAL_ERROR "could not find zlib")
210	endif()
211
212	set(CBOR_LIBRARIES "cbor")
213	set(CRYPTO_LIBRARIES "crypto")
214
215	if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
216		pkg_search_module(UDEV libudev REQUIRED)
217		set(UDEV_NAME "udev")
218		# If using hidapi, use hidapi-hidraw.
219		set(HIDAPI_SUFFIX -hidraw)
220		if(NOT HAVE_CLOCK_GETTIME)
221			# Look for clock_gettime in librt.
222			check_library_exists(rt clock_gettime "time.h"
223			    HAVE_CLOCK_GETTIME)
224			if (HAVE_CLOCK_GETTIME)
225				add_definitions(-DHAVE_CLOCK_GETTIME)
226				set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
227			endif()
228		endif()
229	else()
230		set(NFC_LINUX OFF)
231	endif()
232
233	if(MINGW)
234		# MinGW is stuck with a flavour of C89.
235		add_definitions(-DFIDO_NO_DIAGNOSTIC)
236		add_definitions(-DWC_ERR_INVALID_CHARS=0x80)
237		add_compile_options(-Wno-unused-parameter)
238	endif()
239
240	if(USE_HIDAPI)
241		add_definitions(-DUSE_HIDAPI)
242		pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
243		set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
244	endif()
245
246	if(NFC_LINUX)
247		add_definitions(-DNFC_LINUX)
248	endif()
249
250	if(WIN32)
251		if(USE_WINHELLO)
252			add_definitions(-DUSE_WINHELLO)
253		endif()
254	else()
255		set(USE_WINHELLO OFF)
256	endif()
257
258	add_compile_options(-Wall)
259	add_compile_options(-Wextra)
260	add_compile_options(-Werror)
261	add_compile_options(-Wshadow)
262	add_compile_options(-Wcast-qual)
263	add_compile_options(-Wwrite-strings)
264	add_compile_options(-Wmissing-prototypes)
265	add_compile_options(-Wbad-function-cast)
266	add_compile_options(-pedantic)
267	add_compile_options(-pedantic-errors)
268
269	if(WIN32)
270		add_compile_options(-Wno-type-limits)
271		add_compile_options(-Wno-cast-function-type)
272	endif()
273	if(HAVE_SHORTEN_64_TO_32)
274		add_compile_options(-Wshorten-64-to-32)
275	endif()
276	if(HAVE_STACK_PROTECTOR_ALL)
277		add_compile_options(-fstack-protector-all)
278	endif()
279
280	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2")
281	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer")
282	set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2")
283
284	if(CRYPTO_VERSION VERSION_GREATER_EQUAL 3.0)
285		add_definitions(-DOPENSSL_API_COMPAT=0x10100000L)
286	endif()
287
288	if(FUZZ)
289		add_definitions(-DFIDO_FUZZ)
290	endif()
291
292	if(LIBFUZZER)
293		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
294	endif()
295endif()
296
297# Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
298if(CMAKE_COMPILER_IS_GNUCC)
299	add_compile_options(-Wno-unused-result)
300endif()
301
302# Decide which keyword to use for thread-local storage.
303if(CMAKE_COMPILER_IS_GNUCC OR
304   CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
305   CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
306	set(TLS "__thread")
307elseif(WIN32)
308	set(TLS "__declspec(thread)")
309endif()
310add_definitions(-DTLS=${TLS})
311
312# export list
313if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
314   CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
315	# clang + lld
316	string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
317	    " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm")
318elseif(NOT MSVC)
319	# clang/gcc + gnu ld
320	if(FUZZ)
321		string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
322		    " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/fuzz/export.gnu")
323	else()
324		string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
325		    " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu")
326	endif()
327	if(NOT WIN32)
328		string(CONCAT CMAKE_SHARED_LINKER_FLAGS
329		    ${CMAKE_SHARED_LINKER_FLAGS}
330		    " -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
331		string(CONCAT CMAKE_EXE_LINKER_FLAGS
332		    ${CMAKE_EXE_LINKER_FLAGS}
333		    " -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
334		if(FUZZ)
335			file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS)
336			foreach(s ${WRAPPED_SYMBOLS})
337				string(CONCAT CMAKE_SHARED_LINKER_FLAGS
338				    ${CMAKE_SHARED_LINKER_FLAGS}
339				    " -Wl,--wrap=${s}")
340			endforeach()
341		endif()
342	endif()
343else()
344	string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
345	    " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
346endif()
347
348include_directories(${CMAKE_SOURCE_DIR}/src)
349include_directories(${CBOR_INCLUDE_DIRS})
350include_directories(${CRYPTO_INCLUDE_DIRS})
351include_directories(${HIDAPI_INCLUDE_DIRS})
352include_directories(${UDEV_INCLUDE_DIRS})
353include_directories(${ZLIB_INCLUDE_DIRS})
354
355link_directories(${CBOR_LIBRARY_DIRS})
356link_directories(${CRYPTO_LIBRARY_DIRS})
357link_directories(${HIDAPI_LIBRARY_DIRS})
358link_directories(${UDEV_LIBRARY_DIRS})
359link_directories(${ZLIB_LIBRARY_DIRS})
360
361message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}")
362message(STATUS "BUILD_EXAMPLES: ${BUILD_EXAMPLES}")
363message(STATUS "BUILD_MANPAGES: ${BUILD_MANPAGES}")
364message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
365message(STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}")
366message(STATUS "BUILD_TOOLS: ${BUILD_TOOLS}")
367message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
368message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
369message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
370message(STATUS "CBOR_VERSION: ${CBOR_VERSION}")
371message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
372message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
373message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
374message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
375message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
376message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
377message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
378message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}")
379message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
380message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
381message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
382message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}")
383message(STATUS "FIDO_VERSION: ${FIDO_VERSION}")
384message(STATUS "FUZZ: ${FUZZ}")
385message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")
386message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
387message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}")
388message(STATUS "ZLIB_VERSION: ${ZLIB_VERSION}")
389if(USE_HIDAPI)
390	message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}")
391	message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}")
392	message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
393	message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}")
394endif()
395message(STATUS "LIBFUZZER: ${LIBFUZZER}")
396message(STATUS "TLS: ${TLS}")
397message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
398message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}")
399message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
400message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
401message(STATUS "UDEV_VERSION: ${UDEV_VERSION}")
402message(STATUS "USE_HIDAPI: ${USE_HIDAPI}")
403message(STATUS "USE_WINHELLO: ${USE_WINHELLO}")
404message(STATUS "NFC_LINUX: ${NFC_LINUX}")
405
406subdirs(src)
407if(BUILD_EXAMPLES)
408	subdirs(examples)
409endif()
410if(BUILD_TOOLS)
411	subdirs(tools)
412endif()
413if(BUILD_MANPAGES)
414	subdirs(man)
415endif()
416
417if(NOT WIN32)
418	if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FUZZ)
419		enable_testing()
420		subdirs(regress)
421	endif()
422	if(FUZZ)
423		subdirs(fuzz)
424	endif()
425	if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
426		subdirs(udev)
427	endif()
428endif()
429