diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
new file mode 100644
index 0000000..e83a9d7
--- /dev/null
+++ b/man/CMakeLists.txt
@@ -0,0 +1,417 @@
+# Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+find_program(MANDOC_PATH mandoc)
+find_program(GZIP_PATH gzip)
+
+message(STATUS "MANDOC_PATH: ${MANDOC_PATH}")
+message(STATUS "GZIP_PATH: ${GZIP_PATH}")
+
+list(APPEND MAN_SOURCES
+ eddsa_pk_new.3
+ es256_pk_new.3
+ es384_pk_new.3
+ fido2-assert.1
+ fido2-cred.1
+ fido2-token.1
+ fido_init.3
+ fido_assert_new.3
+ fido_assert_allow_cred.3
+ fido_assert_set_authdata.3
+ fido_assert_verify.3
+ fido_bio_dev_get_info.3
+ fido_bio_enroll_new.3
+ fido_bio_info_new.3
+ fido_bio_template.3
+ fido_cbor_info_new.3
+ fido_cred_new.3
+ fido_cred_exclude.3
+ fido_credman_metadata_new.3
+ fido_cred_set_authdata.3
+ fido_cred_verify.3
+ fido_dev_enable_entattest.3
+ fido_dev_get_assert.3
+ fido_dev_get_touch_begin.3
+ fido_dev_info_manifest.3
+ fido_dev_largeblob_get.3
+ fido_dev_make_cred.3
+ fido_dev_open.3
+ fido_dev_set_io_functions.3
+ fido_dev_set_pin.3
+ fido_strerr.3
+ rs256_pk_new.3
+)
+
+list(APPEND MAN_ALIAS
+ eddsa_pk_new eddsa_pk_free
+ eddsa_pk_new eddsa_pk_from_EVP_PKEY
+ eddsa_pk_new eddsa_pk_from_ptr
+ eddsa_pk_new eddsa_pk_to_EVP_PKEY
+ es256_pk_new es256_pk_free
+ es256_pk_new es256_pk_from_EC_KEY
+ es256_pk_new es256_pk_from_EVP_PKEY
+ es256_pk_new es256_pk_from_ptr
+ es256_pk_new es256_pk_to_EVP_PKEY
+ es384_pk_new es384_pk_free
+ es384_pk_new es384_pk_from_EC_KEY
+ es384_pk_new es384_pk_from_EVP_PKEY
+ es384_pk_new es384_pk_from_ptr
+ es384_pk_new es384_pk_to_EVP_PKEY
+ fido_assert_allow_cred fido_assert_empty_allow_list
+ fido_assert_new fido_assert_authdata_len
+ fido_assert_new fido_assert_authdata_ptr
+ fido_assert_new fido_assert_authdata_raw_len
+ fido_assert_new fido_assert_authdata_raw_ptr
+ fido_assert_new fido_assert_blob_len
+ fido_assert_new fido_assert_blob_ptr
+ fido_assert_new fido_assert_clientdata_hash_len
+ fido_assert_new fido_assert_clientdata_hash_ptr
+ fido_assert_new fido_assert_count
+ fido_assert_new fido_assert_flags
+ fido_assert_new fido_assert_free
+ fido_assert_new fido_assert_hmac_secret_len
+ fido_assert_new fido_assert_hmac_secret_ptr
+ fido_assert_new fido_assert_id_len
+ fido_assert_new fido_assert_id_ptr
+ fido_assert_new fido_assert_largeblob_key_len
+ fido_assert_new fido_assert_largeblob_key_ptr
+ fido_assert_new fido_assert_rp_id
+ fido_assert_new fido_assert_sigcount
+ fido_assert_new fido_assert_sig_len
+ fido_assert_new fido_assert_sig_ptr
+ fido_assert_new fido_assert_user_display_name
+ fido_assert_new fido_assert_user_icon
+ fido_assert_new fido_assert_user_id_len
+ fido_assert_new fido_assert_user_id_ptr
+ fido_assert_new fido_assert_user_name
+ fido_assert_set_authdata fido_assert_set_authdata_raw
+ fido_assert_set_authdata fido_assert_set_clientdata
+ fido_assert_set_authdata fido_assert_set_clientdata_hash
+ fido_assert_set_authdata fido_assert_set_count
+ fido_assert_set_authdata fido_assert_set_extensions
+ fido_assert_set_authdata fido_assert_set_hmac_salt
+ fido_assert_set_authdata fido_assert_set_hmac_secret
+ fido_assert_set_authdata fido_assert_set_rp
+ fido_assert_set_authdata fido_assert_set_sig
+ fido_assert_set_authdata fido_assert_set_up
+ fido_assert_set_authdata fido_assert_set_uv
+ fido_assert_set_authdata fido_assert_set_winhello_appid
+ fido_bio_dev_get_info fido_bio_dev_enroll_begin
+ fido_bio_dev_get_info fido_bio_dev_enroll_cancel
+ fido_bio_dev_get_info fido_bio_dev_enroll_continue
+ fido_bio_dev_get_info fido_bio_dev_enroll_remove
+ fido_bio_dev_get_info fido_bio_dev_get_template_array
+ fido_bio_dev_get_info fido_bio_dev_set_template_name
+ fido_bio_enroll_new fido_bio_enroll_free
+ fido_bio_enroll_new fido_bio_enroll_last_status
+ fido_bio_enroll_new fido_bio_enroll_remaining_samples
+ fido_bio_info_new fido_bio_info_free
+ fido_bio_info_new fido_bio_info_max_samples
+ fido_bio_info_new fido_bio_info_type
+ fido_bio_template fido_bio_template_array_count
+ fido_bio_template fido_bio_template_array_free
+ fido_bio_template fido_bio_template_array_new
+ fido_bio_template fido_bio_template_free
+ fido_bio_template fido_bio_template_id_len
+ fido_bio_template fido_bio_template_id_ptr
+ fido_bio_template fido_bio_template_name
+ fido_bio_template fido_bio_template_new
+ fido_bio_template fido_bio_template_set_id
+ fido_bio_template fido_bio_template_set_name
+ fido_cbor_info_new fido_cbor_info_aaguid_len
+ fido_cbor_info_new fido_cbor_info_aaguid_ptr
+ fido_cbor_info_new fido_cbor_info_algorithm_cose
+ fido_cbor_info_new fido_cbor_info_algorithm_count
+ fido_cbor_info_new fido_cbor_info_algorithm_type
+ fido_cbor_info_new fido_cbor_info_certs_len
+ fido_cbor_info_new fido_cbor_info_certs_name_ptr
+ fido_cbor_info_new fido_cbor_info_certs_value_ptr
+ fido_cbor_info_new fido_cbor_info_extensions_len
+ fido_cbor_info_new fido_cbor_info_extensions_ptr
+ fido_cbor_info_new fido_cbor_info_free
+ fido_cbor_info_new fido_cbor_info_fwversion
+ fido_cbor_info_new fido_cbor_info_maxcredbloblen
+ fido_cbor_info_new fido_cbor_info_maxcredcntlst
+ fido_cbor_info_new fido_cbor_info_maxcredidlen
+ fido_cbor_info_new fido_cbor_info_maxlargeblob
+ fido_cbor_info_new fido_cbor_info_maxmsgsiz
+ fido_cbor_info_new fido_cbor_info_maxrpid_minpinlen
+ fido_cbor_info_new fido_cbor_info_minpinlen
+ fido_cbor_info_new fido_cbor_info_new_pin_required
+ fido_cbor_info_new fido_cbor_info_options_len
+ fido_cbor_info_new fido_cbor_info_options_name_ptr
+ fido_cbor_info_new fido_cbor_info_options_value_ptr
+ fido_cbor_info_new fido_cbor_info_protocols_len
+ fido_cbor_info_new fido_cbor_info_protocols_ptr
+ fido_cbor_info_new fido_cbor_info_rk_remaining
+ fido_cbor_info_new fido_cbor_info_transports_len
+ fido_cbor_info_new fido_cbor_info_transports_ptr
+ fido_cbor_info_new fido_cbor_info_uv_attempts
+ fido_cbor_info_new fido_cbor_info_uv_modality
+ fido_cbor_info_new fido_cbor_info_versions_len
+ fido_cbor_info_new fido_cbor_info_versions_ptr
+ fido_cbor_info_new fido_dev_get_cbor_info
+ fido_cred_exclude fido_cred_empty_exclude_list
+ fido_cred_new fido_cred_aaguid_len
+ fido_cred_new fido_cred_aaguid_ptr
+ fido_cred_new fido_cred_attstmt_len
+ fido_cred_new fido_cred_attstmt_ptr
+ fido_cred_new fido_cred_authdata_len
+ fido_cred_new fido_cred_authdata_ptr
+ fido_cred_new fido_cred_authdata_raw_len
+ fido_cred_new fido_cred_authdata_raw_ptr
+ fido_cred_new fido_cred_clientdata_hash_len
+ fido_cred_new fido_cred_clientdata_hash_ptr
+ fido_cred_new fido_cred_display_name
+ fido_cred_new fido_cred_flags
+ fido_cred_new fido_cred_fmt
+ fido_cred_new fido_cred_free
+ fido_cred_new fido_cred_id_len
+ fido_cred_new fido_cred_id_ptr
+ fido_cred_new fido_cred_largeblob_key_len
+ fido_cred_new fido_cred_largeblob_key_ptr
+ fido_cred_new fido_cred_pin_minlen
+ fido_cred_new fido_cred_prot
+ fido_cred_new fido_cred_pubkey_len
+ fido_cred_new fido_cred_pubkey_ptr
+ fido_cred_new fido_cred_rp_id
+ fido_cred_new fido_cred_rp_name
+ fido_cred_new fido_cred_sigcount
+ fido_cred_new fido_cred_sig_len
+ fido_cred_new fido_cred_sig_ptr
+ fido_cred_new fido_cred_type
+ fido_cred_new fido_cred_user_id_len
+ fido_cred_new fido_cred_user_id_ptr
+ fido_cred_new fido_cred_user_name
+ fido_cred_new fido_cred_x5c_len
+ fido_cred_new fido_cred_x5c_list_count
+ fido_cred_new fido_cred_x5c_list_len
+ fido_cred_new fido_cred_x5c_list_ptr
+ fido_cred_new fido_cred_x5c_ptr
+ fido_cred_verify fido_cred_verify_self
+ fido_credman_metadata_new fido_credman_del_dev_rk
+ fido_credman_metadata_new fido_credman_get_dev_metadata
+ fido_credman_metadata_new fido_credman_get_dev_rk
+ fido_credman_metadata_new fido_credman_get_dev_rp
+ fido_credman_metadata_new fido_credman_metadata_free
+ fido_credman_metadata_new fido_credman_rk
+ fido_credman_metadata_new fido_credman_rk_count
+ fido_credman_metadata_new fido_credman_rk_existing
+ fido_credman_metadata_new fido_credman_rk_free
+ fido_credman_metadata_new fido_credman_rk_new
+ fido_credman_metadata_new fido_credman_rk_remaining
+ fido_credman_metadata_new fido_credman_rp_count
+ fido_credman_metadata_new fido_credman_rp_free
+ fido_credman_metadata_new fido_credman_rp_id
+ fido_credman_metadata_new fido_credman_rp_id_hash_len
+ fido_credman_metadata_new fido_credman_rp_id_hash_ptr
+ fido_credman_metadata_new fido_credman_rp_name
+ fido_credman_metadata_new fido_credman_rp_new
+ fido_credman_metadata_new fido_credman_set_dev_rk
+ fido_cred_set_authdata fido_cred_set_attstmt
+ fido_cred_set_authdata fido_cred_set_attobj
+ fido_cred_set_authdata fido_cred_set_authdata_raw
+ fido_cred_set_authdata fido_cred_set_blob
+ fido_cred_set_authdata fido_cred_set_clientdata
+ fido_cred_set_authdata fido_cred_set_clientdata_hash
+ fido_cred_set_authdata fido_cred_set_extensions
+ fido_cred_set_authdata fido_cred_set_fmt
+ fido_cred_set_authdata fido_cred_set_id
+ fido_cred_set_authdata fido_cred_set_pin_minlen
+ fido_cred_set_authdata fido_cred_set_prot
+ fido_cred_set_authdata fido_cred_set_rk
+ fido_cred_set_authdata fido_cred_set_rp
+ fido_cred_set_authdata fido_cred_set_sig
+ fido_cred_set_authdata fido_cred_set_type
+ fido_cred_set_authdata fido_cred_set_user
+ fido_cred_set_authdata fido_cred_set_uv
+ fido_cred_set_authdata fido_cred_set_x509
+ fido_dev_enable_entattest fido_dev_toggle_always_uv
+ fido_dev_enable_entattest fido_dev_force_pin_change
+ fido_dev_enable_entattest fido_dev_set_pin_minlen
+ fido_dev_enable_entattest fido_dev_set_pin_minlen_rpid
+ fido_dev_get_touch_begin fido_dev_get_touch_status
+ fido_dev_info_manifest fido_dev_info_free
+ fido_dev_info_manifest fido_dev_info_manufacturer_string
+ fido_dev_info_manifest fido_dev_info_new
+ fido_dev_info_manifest fido_dev_info_path
+ fido_dev_info_manifest fido_dev_info_product
+ fido_dev_info_manifest fido_dev_info_product_string
+ fido_dev_info_manifest fido_dev_info_ptr
+ fido_dev_info_manifest fido_dev_info_set
+ fido_dev_info_manifest fido_dev_info_vendor
+ fido_dev_open fido_dev_build
+ fido_dev_open fido_dev_cancel
+ fido_dev_open fido_dev_close
+ fido_dev_open fido_dev_flags
+ fido_dev_open fido_dev_force_fido2
+ fido_dev_open fido_dev_force_u2f
+ fido_dev_open fido_dev_free
+ fido_dev_open fido_dev_has_pin
+ fido_dev_open fido_dev_has_uv
+ fido_dev_open fido_dev_is_fido2
+ fido_dev_open fido_dev_is_winhello
+ fido_dev_open fido_dev_major
+ fido_dev_open fido_dev_minor
+ fido_dev_open fido_dev_new
+ fido_dev_open fido_dev_new_with_info
+ fido_dev_open fido_dev_open_with_info
+ fido_dev_open fido_dev_protocol
+ fido_dev_open fido_dev_supports_cred_prot
+ fido_dev_open fido_dev_supports_credman
+ fido_dev_open fido_dev_supports_permissions
+ fido_dev_open fido_dev_supports_pin
+ fido_dev_open fido_dev_supports_uv
+ fido_dev_set_pin fido_dev_get_retry_count
+ fido_dev_set_pin fido_dev_get_uv_retry_count
+ fido_dev_set_pin fido_dev_reset
+ fido_dev_set_io_functions fido_dev_io_handle
+ fido_dev_set_io_functions fido_dev_set_sigmask
+ fido_dev_set_io_functions fido_dev_set_timeout
+ fido_dev_set_io_functions fido_dev_set_transport_functions
+ fido_dev_largeblob_get fido_dev_largeblob_set
+ fido_dev_largeblob_get fido_dev_largeblob_remove
+ fido_dev_largeblob_get fido_dev_largeblob_get_array
+ fido_dev_largeblob_get fido_dev_largeblob_set_array
+ fido_init fido_set_log_handler
+ rs256_pk_new rs256_pk_free
+ rs256_pk_new rs256_pk_from_ptr
+ rs256_pk_new rs256_pk_from_EVP_PKEY
+ rs256_pk_new rs256_pk_from_RSA
+ rs256_pk_new rs256_pk_to_EVP_PKEY
+)
+
+list(LENGTH MAN_ALIAS MAN_ALIAS_LEN)
+math(EXPR MAN_ALIAS_MAX "${MAN_ALIAS_LEN} - 2")
+
+# man_copy
+foreach(f ${MAN_SOURCES})
+ add_custom_command(OUTPUT ${f}
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/man/${f} .
+ DEPENDS ${f})
+ list(APPEND COPY_FILES ${f})
+endforeach()
+
+# man_lint
+foreach(f ${MAN_SOURCES})
+ add_custom_command(OUTPUT ${f}.lint
+ COMMAND mandoc -T lint -W warning ${f} > ${f}.lint
+ DEPENDS ${f})
+ list(APPEND LINT_FILES ${f}.lint)
+endforeach()
+
+# man_html
+foreach(f ${MAN_SOURCES})
+ string(REGEX REPLACE "\\.[13]$" "" g ${f})
+ add_custom_command(OUTPUT ${g}.html
+ COMMAND mandoc -T html -O man="%N.html",style=style.css -I os="Yubico AB" ${f} > ${g}.html
+ DEPENDS ${f})
+ list(APPEND HTML_FILES ${g}.html)
+endforeach()
+
+# man_html_partial
+foreach(f ${MAN_SOURCES})
+ string(REGEX REPLACE "\\.[13]$" "" g ${f})
+ add_custom_command(OUTPUT ${g}.partial
+ COMMAND cat ${PROJECT_SOURCE_DIR}/man/dyc.css > ${g}.partial
+ COMMAND mandoc -T html -O man="%N.html",fragment ${f} >> ${g}.partial
+ DEPENDS ${f})
+ list(APPEND HTML_PARTIAL_FILES ${g}.partial)
+endforeach()
+
+# man_gzip
+foreach(f ${MAN_SOURCES})
+ add_custom_command(OUTPUT ${f}.gz
+ COMMAND gzip -cn ${f} > ${f}.gz
+ DEPENDS ${f})
+ list(APPEND GZ_FILES ${f}.gz)
+endforeach()
+
+macro(define_symlink_target NAME EXT)
+ foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
+ math(EXPR j "${i} + 1")
+ list(GET MAN_ALIAS ${i} SRC)
+ list(GET MAN_ALIAS ${j} DST)
+ add_custom_command(OUTPUT ${DST}.${EXT}
+ COMMAND ln -sf ${SRC}.${EXT} ${DST}.${EXT})
+ list(APPEND ${NAME}_LINK_FILES ${DST}.${EXT})
+ endforeach()
+ add_custom_target(${NAME} DEPENDS ${${NAME}_LINK_FILES})
+endmacro()
+
+add_custom_target(man_copy DEPENDS ${COPY_FILES})
+add_custom_target(man_lint DEPENDS ${LINT_FILES})
+add_custom_target(man_html DEPENDS ${HTML_FILES})
+add_custom_target(man_html_partial DEPENDS ${HTML_PARTIAL_FILES})
+add_custom_target(man_gzip DEPENDS ${GZ_FILES})
+
+define_symlink_target(man_symlink 3)
+define_symlink_target(man_symlink_html html)
+define_symlink_target(man_symlink_html_partial partial)
+define_symlink_target(man_symlink_gzip 3.gz)
+
+add_dependencies(man_symlink man_copy)
+add_dependencies(man_lint man_symlink)
+add_dependencies(man_html man_lint)
+add_dependencies(man_symlink_html man_html)
+add_dependencies(man_html_partial man_lint)
+add_dependencies(man_symlink_html_partial man_html_partial)
+add_custom_target(man ALL)
+
+if(MANDOC_PATH)
+ add_dependencies(man man_symlink_html)
+ add_dependencies(man_gzip man_lint)
+ install(FILES ${PROJECT_SOURCE_DIR}/man/style.css
+ DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
+ foreach(f ${MAN_SOURCES})
+ string(REGEX REPLACE "\\.[13]$" "" f ${f})
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.html
+ DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
+ endforeach()
+ foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
+ math(EXPR j "${i} + 1")
+ list(GET MAN_ALIAS ${j} DST)
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.html
+ DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
+ endforeach()
+endif()
+
+if(GZIP_PATH)
+ add_dependencies(man_gzip man_copy)
+ add_dependencies(man_symlink_gzip man_gzip)
+ add_dependencies(man man_symlink_gzip)
+ foreach(f ${MAN_SOURCES})
+ if (${f} MATCHES ".1$")
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.gz
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+ elseif(${f} MATCHES ".3$")
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.gz
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
+ endif()
+ endforeach()
+ foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
+ math(EXPR j "${i} + 1")
+ list(GET MAN_ALIAS ${j} DST)
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.3.gz
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
+ endforeach()
+else()
+ add_dependencies(man man_symlink)
+ foreach(f ${MAN_SOURCES})
+ if (${f} MATCHES ".1$")
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
+ elseif(${f} MATCHES ".3$")
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
+ endif()
+ endforeach()
+ foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
+ math(EXPR j "${i} + 1")
+ list(GET MAN_ALIAS ${j} DST)
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.3
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
+ endforeach()
+endif()
diff --git a/man/NOTES b/man/NOTES
new file mode 100644
index 0000000..5cba436
--- /dev/null
+++ b/man/NOTES
@@ -0,0 +1,7 @@
+To generate .partial files for https://developers.yubico.com/:
+
+$ make -C build man_symlink_html_partial
+$ (cd build/man && pax -p p -r -w *.partial /tmp/partial)
+
+Use mandoc 1.14.4. Otherwise, adjust dyc.css to mandoc's HTML
+output.
diff --git a/man/check.sh b/man/check.sh
new file mode 100644
index 0000000..d969a7a
--- /dev/null
+++ b/man/check.sh
@@ -0,0 +1,43 @@
+#!/bin/sh -u
+
+# Copyright (c) 2022 Yubico AB. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+T=$(mktemp -d) || exit 1
+find . -maxdepth 1 -type f -name '*.3' -print0 > "$T/files"
+
+xargs -0 awk '/^.Sh NAME/,/^.Nd/' < "$T/files" | \
+ awk '/^.Nm/ { print $2 }' | sort -u > "$T/Nm"
+xargs -0 awk '/^.Fn/ { print $2 }' < "$T/files" | sort -u > "$T/Fn"
+(cd "$T" && diff -u Nm Fn)
+
+cut -c2- ../src/export.llvm | sort > "$T/exports"
+(cd "$T" && diff -u Nm exports)
+
+awk '/^list\(APPEND MAN_SOURCES/,/^\)/' CMakeLists.txt | \
+ awk '/.3$/ { print $1 }' | sort > "$T/listed_sources"
+xargs -0 -n1 basename < "$T/files" | sort > "$T/actual_sources"
+(cd "$T" && diff -u listed_sources actual_sources)
+
+awk '/^list\(APPEND MAN_ALIAS/,/^\)/' CMakeLists.txt | \
+ sed '1d;$d' | awk '{ print $1, $2 }' | sort > "$T/listed_aliases"
+xargs -0 grep -o "^.Fn [A-Za-z0-9_]* \"" < "$T/files" | \
+ cut -c3- | sed 's/\.3:\.Fn//;s/ "//' | awk '$1 != $2' | \
+ sort > "$T/actual_aliases"
+(cd "$T" && diff -u listed_aliases actual_aliases)
+
+xargs -0 grep -hB1 "^.Fn [A-Za-z0-9_]* \"" < "$T/files" | \
+ sed -E 's/^.F[tn] //;s/\*[^"\*]+"/\*"/g;s/ [^" \*]+"/"/g;/^--$/d' | \
+ paste -d " " - - | sed 's/\* /\*/' | sort > "$T/documented_prototypes"
+while read -r f; do
+ awk "/\/\*/ { next } /$f\(/,/;/" ../src/fido.h ../src/fido/*.h | \
+ sed -E 's/^[ ]+//;s/[ ]+/ /' | tr '\n' ' ' | \
+ sed 's/(/ "/;s/, /" "/g;s/);/"/;s/ $/\n/'
+done < "$T/exports" | sort > "$T/actual_prototypes"
+(cd "$T" && diff -u documented_prototypes actual_prototypes)
+
+(cd "$T" && rm files Nm Fn exports listed_sources actual_sources \
+ listed_aliases actual_aliases documented_prototypes actual_prototypes)
+rmdir -- "$T"
diff --git a/man/dyc.css b/man/dyc.css
new file mode 100644
index 0000000..1ff5b59
--- /dev/null
+++ b/man/dyc.css
@@ -0,0 +1,14 @@
+
diff --git a/man/eddsa_pk_new.3 b/man/eddsa_pk_new.3
new file mode 100644
index 0000000..428d724
--- /dev/null
+++ b/man/eddsa_pk_new.3
@@ -0,0 +1,146 @@
+.\" Copyright (c) 2019-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt EDDSA_PK_NEW 3
+.Os
+.Sh NAME
+.Nm eddsa_pk_new ,
+.Nm eddsa_pk_free ,
+.Nm eddsa_pk_from_EVP_PKEY ,
+.Nm eddsa_pk_from_ptr ,
+.Nm eddsa_pk_to_EVP_PKEY
+.Nd FIDO2 COSE EDDSA API
+.Sh SYNOPSIS
+.In openssl/evp.h
+.In fido/eddsa.h
+.Ft eddsa_pk_t *
+.Fn eddsa_pk_new "void"
+.Ft void
+.Fn eddsa_pk_free "eddsa_pk_t **pkp"
+.Ft int
+.Fn eddsa_pk_from_EVP_PKEY "eddsa_pk_t *pk" "const EVP_PKEY *pkey"
+.Ft int
+.Fn eddsa_pk_from_ptr "eddsa_pk_t *pk" "const void *ptr" "size_t len"
+.Ft EVP_PKEY *
+.Fn eddsa_pk_to_EVP_PKEY "const eddsa_pk_t *pk"
+.Sh DESCRIPTION
+EDDSA is the name given in the CBOR Object Signing and Encryption
+(COSE) RFC to EDDSA over Curve25519 with SHA-512.
+The COSE EDDSA API of
+.Em libfido2
+is an auxiliary API with routines to convert between the different
+EDDSA public key types used in
+.Em libfido2
+and
+.Em OpenSSL .
+.Pp
+In
+.Em libfido2 ,
+EDDSA public keys are abstracted by the
+.Vt eddsa_pk_t
+type.
+.Pp
+The
+.Fn eddsa_pk_new
+function returns a pointer to a newly allocated, empty
+.Vt eddsa_pk_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn eddsa_pk_free
+function releases the memory backing
+.Fa *pkp ,
+where
+.Fa *pkp
+must have been previously allocated by
+.Fn eddsa_pk_new .
+On return,
+.Fa *pkp
+is set to NULL.
+Either
+.Fa pkp
+or
+.Fa *pkp
+may be NULL, in which case
+.Fn eddsa_pk_free
+is a NOP.
+.Pp
+The
+.Fn eddsa_pk_from_EVP_PKEY
+function fills
+.Fa pk
+with the contents of
+.Fa pkey .
+No references to
+.Fa pkey
+are kept.
+.Pp
+The
+.Fn eddsa_pk_from_ptr
+function fills
+.Fa pk
+with the contents of
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+No references to
+.Fa ptr
+are kept.
+.Pp
+The
+.Fn eddsa_pk_to_EVP_PKEY
+function converts
+.Fa pk
+to a newly allocated
+.Fa EVP_PKEY
+type with a reference count of 1.
+No internal references to the returned pointer are kept.
+If an error occurs,
+.Fn eddsa_pk_to_EVP_PKEY
+returns NULL.
+.Sh RETURN VALUES
+The
+.Fn eddsa_pk_from_EVP_PKEY
+and
+.Fn eddsa_pk_from_ptr
+functions return
+.Dv FIDO_OK
+on success.
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr es256_pk_new 3 ,
+.Xr es384_pk_new 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_cred_pubkey_ptr 3 ,
+.Xr rs256_pk_new 3
diff --git a/man/es256_pk_new.3 b/man/es256_pk_new.3
new file mode 100644
index 0000000..7d6be4d
--- /dev/null
+++ b/man/es256_pk_new.3
@@ -0,0 +1,164 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt ES256_PK_NEW 3
+.Os
+.Sh NAME
+.Nm es256_pk_new ,
+.Nm es256_pk_free ,
+.Nm es256_pk_from_EC_KEY ,
+.Nm es256_pk_from_EVP_PKEY ,
+.Nm es256_pk_from_ptr ,
+.Nm es256_pk_to_EVP_PKEY
+.Nd FIDO2 COSE ES256 API
+.Sh SYNOPSIS
+.In openssl/ec.h
+.In fido/es256.h
+.Ft es256_pk_t *
+.Fn es256_pk_new "void"
+.Ft void
+.Fn es256_pk_free "es256_pk_t **pkp"
+.Ft int
+.Fn es256_pk_from_EC_KEY "es256_pk_t *pk" "const EC_KEY *ec"
+.Ft int
+.Fn es256_pk_from_EVP_PKEY "es256_pk_t *pk" "const EVP_PKEY *pkey"
+.Ft int
+.Fn es256_pk_from_ptr "es256_pk_t *pk" "const void *ptr" "size_t len"
+.Ft EVP_PKEY *
+.Fn es256_pk_to_EVP_PKEY "const es256_pk_t *pk"
+.Sh DESCRIPTION
+ES256 is the name given in the CBOR Object Signing and Encryption
+(COSE) RFC to ECDSA over P-256 with SHA-256.
+The COSE ES256 API of
+.Em libfido2
+is an auxiliary API with routines to convert between the different
+ECDSA public key types used in
+.Em libfido2
+and
+.Em OpenSSL .
+.Pp
+In
+.Em libfido2 ,
+ES256 public keys are abstracted by the
+.Vt es256_pk_t
+type.
+.Pp
+The
+.Fn es256_pk_new
+function returns a pointer to a newly allocated, empty
+.Vt es256_pk_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn es256_pk_free
+function releases the memory backing
+.Fa *pkp ,
+where
+.Fa *pkp
+must have been previously allocated by
+.Fn es256_pk_new .
+On return,
+.Fa *pkp
+is set to NULL.
+Either
+.Fa pkp
+or
+.Fa *pkp
+may be NULL, in which case
+.Fn es256_pk_free
+is a NOP.
+.Pp
+The
+.Fn es256_pk_from_EC_KEY
+function fills
+.Fa pk
+with the contents of
+.Fa ec .
+No references to
+.Fa ec
+are kept.
+.Pp
+The
+.Fn es256_pk_from_EVP_PKEY
+function fills
+.Fa pk
+with the contents of
+.Fa pkey .
+No references to
+.Fa pkey
+are kept.
+.Pp
+The
+.Fn es256_pk_from_ptr
+function fills
+.Fa pk
+with the contents of
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+The
+.Fa ptr
+pointer may point to an uncompressed point, or to the
+concatenation of the x and y coordinates.
+No references to
+.Fa ptr
+are kept.
+.Pp
+The
+.Fn es256_pk_to_EVP_PKEY
+function converts
+.Fa pk
+to a newly allocated
+.Fa EVP_PKEY
+type with a reference count of 1.
+No internal references to the returned pointer are kept.
+If an error occurs,
+.Fn es256_pk_to_EVP_PKEY
+returns NULL.
+.Sh RETURN VALUES
+The
+.Fn es256_pk_from_EC_KEY ,
+.Fn es256_pk_from_EVP_PKEY ,
+and
+.Fn es256_pk_from_ptr
+functions return
+.Dv FIDO_OK
+on success.
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr eddsa_pk_new 3 ,
+.Xr es384_pk_new 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_cred_pubkey_ptr 3 ,
+.Xr rs256_pk_new 3
diff --git a/man/es384_pk_new.3 b/man/es384_pk_new.3
new file mode 100644
index 0000000..e865913
--- /dev/null
+++ b/man/es384_pk_new.3
@@ -0,0 +1,164 @@
+.\" Copyright (c) 2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt ES384_PK_NEW 3
+.Os
+.Sh NAME
+.Nm es384_pk_new ,
+.Nm es384_pk_free ,
+.Nm es384_pk_from_EC_KEY ,
+.Nm es384_pk_from_EVP_PKEY ,
+.Nm es384_pk_from_ptr ,
+.Nm es384_pk_to_EVP_PKEY
+.Nd FIDO2 COSE ES384 API
+.Sh SYNOPSIS
+.In openssl/ec.h
+.In fido/es384.h
+.Ft es384_pk_t *
+.Fn es384_pk_new "void"
+.Ft void
+.Fn es384_pk_free "es384_pk_t **pkp"
+.Ft int
+.Fn es384_pk_from_EC_KEY "es384_pk_t *pk" "const EC_KEY *ec"
+.Ft int
+.Fn es384_pk_from_EVP_PKEY "es384_pk_t *pk" "const EVP_PKEY *pkey"
+.Ft int
+.Fn es384_pk_from_ptr "es384_pk_t *pk" "const void *ptr" "size_t len"
+.Ft EVP_PKEY *
+.Fn es384_pk_to_EVP_PKEY "const es384_pk_t *pk"
+.Sh DESCRIPTION
+ES384 is the name given in the CBOR Object Signing and Encryption
+(COSE) RFC to ECDSA over P-384 with SHA-384.
+The COSE ES384 API of
+.Em libfido2
+is an auxiliary API with routines to convert between the different
+ECDSA public key types used in
+.Em libfido2
+and
+.Em OpenSSL .
+.Pp
+In
+.Em libfido2 ,
+ES384 public keys are abstracted by the
+.Vt es384_pk_t
+type.
+.Pp
+The
+.Fn es384_pk_new
+function returns a pointer to a newly allocated, empty
+.Vt es384_pk_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn es384_pk_free
+function releases the memory backing
+.Fa *pkp ,
+where
+.Fa *pkp
+must have been previously allocated by
+.Fn es384_pk_new .
+On return,
+.Fa *pkp
+is set to NULL.
+Either
+.Fa pkp
+or
+.Fa *pkp
+may be NULL, in which case
+.Fn es384_pk_free
+is a NOP.
+.Pp
+The
+.Fn es384_pk_from_EC_KEY
+function fills
+.Fa pk
+with the contents of
+.Fa ec .
+No references to
+.Fa ec
+are kept.
+.Pp
+The
+.Fn es384_pk_from_EVP_PKEY
+function fills
+.Fa pk
+with the contents of
+.Fa pkey .
+No references to
+.Fa pkey
+are kept.
+.Pp
+The
+.Fn es384_pk_from_ptr
+function fills
+.Fa pk
+with the contents of
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+The
+.Fa ptr
+pointer may point to an uncompressed point, or to the
+concatenation of the x and y coordinates.
+No references to
+.Fa ptr
+are kept.
+.Pp
+The
+.Fn es384_pk_to_EVP_PKEY
+function converts
+.Fa pk
+to a newly allocated
+.Fa EVP_PKEY
+type with a reference count of 1.
+No internal references to the returned pointer are kept.
+If an error occurs,
+.Fn es384_pk_to_EVP_PKEY
+returns NULL.
+.Sh RETURN VALUES
+The
+.Fn es384_pk_from_EC_KEY ,
+.Fn es384_pk_from_EVP_PKEY ,
+and
+.Fn es384_pk_from_ptr
+functions return
+.Dv FIDO_OK
+on success.
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr eddsa_pk_new 3 ,
+.Xr es256_pk_new 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_cred_pubkey_ptr 3 ,
+.Xr rs256_pk_new 3
diff --git a/man/fido2-assert.1 b/man/fido2-assert.1
new file mode 100644
index 0000000..882b7ab
--- /dev/null
+++ b/man/fido2-assert.1
@@ -0,0 +1,286 @@
+.\" Copyright (c) 2018-2023 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 3 2023 $
+.Dt FIDO2-ASSERT 1
+.Os
+.Sh NAME
+.Nm fido2-assert
+.Nd get/verify a FIDO2 assertion
+.Sh SYNOPSIS
+.Nm
+.Fl G
+.Op Fl bdhpruvw
+.Op Fl t Ar option
+.Op Fl i Ar input_file
+.Op Fl o Ar output_file
+.Ar device
+.Nm
+.Fl V
+.Op Fl dhpv
+.Op Fl i Ar input_file
+.Ar key_file
+.Op Ar type
+.Sh DESCRIPTION
+.Nm
+gets or verifies a FIDO2 assertion.
+.Pp
+The input of
+.Nm
+is defined by the parameters of the assertion to be obtained/verified.
+See the
+.Sx INPUT FORMAT
+section for details.
+.Pp
+The output of
+.Nm
+is defined by the result of the selected operation.
+See the
+.Sx OUTPUT FORMAT
+section for details.
+.Pp
+If an assertion is successfully obtained or verified,
+.Nm
+exits 0.
+Otherwise,
+.Nm
+exits 1.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl G
+Tells
+.Nm
+to obtain a new assertion from
+.Ar device .
+.It Fl V
+Tells
+.Nm
+to verify an assertion using the PEM-encoded public key in
+.Ar key_file
+of type
+.Ar type ,
+where
+.Ar type
+may be
+.Em es256
+(denoting ECDSA over NIST P-256 with SHA-256),
+.Em rs256
+(denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or
+.Em eddsa
+(denoting EDDSA over Curve25519 with SHA-512).
+If
+.Ar type
+is not specified,
+.Em es256
+is assumed.
+.It Fl b
+Request the credential's
+.Dq largeBlobKey ,
+a 32-byte symmetric key associated with the asserted credential.
+.It Fl h
+If obtaining an assertion, enable the FIDO2 hmac-secret
+extension.
+If verifying an assertion, check whether the extension data bit was
+signed by the authenticator.
+.It Fl d
+Causes
+.Nm
+to emit debugging output on
+.Em stderr .
+.It Fl i Ar input_file
+Tells
+.Nm
+to read the parameters of the assertion from
+.Ar input_file
+instead of
+.Em stdin .
+.It Fl o Ar output_file
+Tells
+.Nm
+to write output on
+.Ar output_file
+instead of
+.Em stdout .
+.It Fl p
+If obtaining an assertion, request user presence.
+If verifying an assertion, check whether the user presence bit was
+signed by the authenticator.
+.It Fl r
+Obtain an assertion using a resident credential.
+If
+.Fl r
+is specified,
+.Nm
+will not expect a credential id in its input, and may output
+multiple assertions.
+Resident credentials are called
+.Dq discoverable credentials
+in CTAP 2.1.
+.It Fl t Ar option
+Toggles a key/value
+.Ar option ,
+where
+.Ar option
+is a string of the form
+.Dq key=value .
+The options supported at present are:
+.Bl -tag -width Ds
+.It Cm up Ns = Ns Ar true|false
+Asks the authenticator for user presence to be enabled or disabled.
+.It Cm uv Ns = Ns Ar true|false
+Asks the authenticator for user verification to be enabled or
+disabled.
+.It Cm pin Ns = Ns Ar true|false
+Tells
+.Nm
+whether to prompt for a PIN and request user verification.
+.El
+.Pp
+The
+.Fl t
+option may be specified multiple times.
+.It Fl u
+Obtain an assertion using U2F.
+By default,
+.Nm
+will use FIDO2 if supported by the authenticator, and fallback to
+U2F otherwise.
+.It Fl v
+If obtaining an assertion, prompt the user for a PIN and request
+user verification from the authenticator.
+If verifying an assertion, check whether the user verification bit
+was signed by the authenticator.
+.It Fl w
+Tells
+.Nm
+that the first line of input when obtaining an assertion shall be
+interpreted as unhashed client data.
+This is required by Windows Hello, which calculates the client data hash
+internally.
+.El
+.Pp
+If a
+.Em tty
+is available,
+.Nm
+will use it to obtain the PIN.
+Otherwise,
+.Em stdin
+is used.
+.Sh INPUT FORMAT
+The input of
+.Nm
+consists of base64 blobs and UTF-8 strings separated
+by newline characters ('\\n').
+.Pp
+When obtaining an assertion,
+.Nm
+expects its input to consist of:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+credential id, if credential not resident (base64 blob);
+.It
+hmac salt, if the FIDO2 hmac-secret extension is enabled
+(base64 blob);
+.El
+.Pp
+When verifying an assertion,
+.Nm
+expects its input to consist of:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+authenticator data (base64 blob);
+.It
+assertion signature (base64 blob);
+.El
+.Pp
+UTF-8 strings passed to
+.Nm
+must not contain embedded newline or NUL characters.
+.Sh OUTPUT FORMAT
+The output of
+.Nm
+consists of base64 blobs and UTF-8 strings separated
+by newline characters ('\\n').
+.Pp
+For each generated assertion,
+.Nm
+outputs:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+authenticator data (base64 blob);
+.It
+assertion signature (base64 blob);
+.It
+user id, if credential resident (base64 blob);
+.It
+hmac secret, if the FIDO2 hmac-secret extension is enabled
+(base64 blob);
+.It
+the credential's associated 32-byte symmetric key
+.Pq Dq largeBlobKey ,
+if requested (base64 blob).
+.El
+.Pp
+When verifying an assertion,
+.Nm
+produces no output.
+.Sh EXAMPLES
+Assuming
+.Pa cred
+contains a
+.Em es256
+credential created according to the steps outlined in
+.Xr fido2-cred 1 ,
+obtain an assertion from an authenticator at
+.Pa /dev/hidraw5
+and verify it:
+.Pp
+.Dl $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param
+.Dl $ echo relying party >> assert_param
+.Dl $ head -1 cred >> assert_param
+.Dl $ tail -n +2 cred > pubkey
+.Dl $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey es256
+.Sh SEE ALSO
+.Xr fido2-cred 1 ,
+.Xr fido2-token 1
diff --git a/man/fido2-cred.1 b/man/fido2-cred.1
new file mode 100644
index 0000000..3f181db
--- /dev/null
+++ b/man/fido2-cred.1
@@ -0,0 +1,297 @@
+.\" Copyright (c) 2018-2023 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 3 2023 $
+.Dt FIDO2-CRED 1
+.Os
+.Sh NAME
+.Nm fido2-cred
+.Nd make/verify a FIDO2 credential
+.Sh SYNOPSIS
+.Nm
+.Fl M
+.Op Fl bdhqruvw
+.Op Fl c Ar cred_protect
+.Op Fl i Ar input_file
+.Op Fl o Ar output_file
+.Ar device
+.Op Ar type
+.Nm
+.Fl V
+.Op Fl dhv
+.Op Fl c Ar cred_protect
+.Op Fl i Ar input_file
+.Op Fl o Ar output_file
+.Op Ar type
+.Sh DESCRIPTION
+.Nm
+makes or verifies a FIDO2 credential.
+.Pp
+A credential
+.Ar type
+may be
+.Em es256
+(denoting ECDSA over NIST P-256 with SHA-256),
+.Em rs256
+(denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or
+.Em eddsa
+(denoting EDDSA over Curve25519 with SHA-512).
+If
+.Ar type
+is not specified,
+.Em es256
+is assumed.
+.Pp
+When making a credential, the authenticator may require the user
+to authenticate with a PIN.
+If the
+.Fl q
+option is not specified,
+.Nm
+will prompt the user for the PIN.
+If a
+.Em tty
+is available,
+.Nm
+will use it to obtain the PIN.
+Otherwise,
+.Em stdin
+is used.
+.Pp
+The input of
+.Nm
+is defined by the parameters of the credential to be made/verified.
+See the
+.Sx INPUT FORMAT
+section for details.
+.Pp
+The output of
+.Nm
+is defined by the result of the selected operation.
+See the
+.Sx OUTPUT FORMAT
+section for details.
+.Pp
+If a credential is successfully created or verified,
+.Nm
+exits 0.
+Otherwise,
+.Nm
+exits 1.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl M
+Tells
+.Nm
+to make a new credential on
+.Ar device .
+.It Fl V
+Tells
+.Nm
+to verify a credential.
+.It Fl b
+Request the credential's
+.Dq largeBlobKey ,
+a 32-byte symmetric key associated with the generated credential.
+.It Fl c Ar cred_protect
+If making a credential, set the credential's protection level to
+.Ar cred_protect ,
+where
+.Ar cred_protect
+is the credential's protection level in decimal notation.
+Please refer to
+.In fido/param.h
+for the set of possible values.
+If verifying a credential, check whether the credential's protection
+level was signed by the authenticator as
+.Ar cred_protect .
+.It Fl d
+Causes
+.Nm
+to emit debugging output on
+.Em stderr .
+.It Fl h
+If making a credential, enable the FIDO2 hmac-secret extension.
+If verifying a credential, check whether the extension data bit was
+signed by the authenticator.
+.It Fl i Ar input_file
+Tells
+.Nm
+to read the parameters of the credential from
+.Ar input_file
+instead of
+.Em stdin .
+.It Fl o Ar output_file
+Tells
+.Nm
+to write output on
+.Ar output_file
+instead of
+.Em stdout .
+.It Fl q
+Tells
+.Nm
+to be quiet.
+If a PIN is required and
+.Fl q
+is specified,
+.Nm
+will fail.
+.It Fl r
+Create a resident credential.
+Resident credentials are called
+.Dq discoverable credentials
+in CTAP 2.1.
+.It Fl u
+Create a U2F credential.
+By default,
+.Nm
+will use FIDO2 if supported by the authenticator, and fallback to
+U2F otherwise.
+.It Fl v
+If making a credential, request user verification.
+If verifying a credential, check whether the user verification bit
+was signed by the authenticator.
+.It Fl w
+Tells
+.Nm
+that the first line of input when making a credential shall be
+interpreted as unhashed client data.
+This is required by Windows Hello, which calculates the client data hash
+internally.
+.El
+.Sh INPUT FORMAT
+The input of
+.Nm
+consists of base64 blobs and UTF-8 strings separated
+by newline characters ('\\n').
+.Pp
+When making a credential,
+.Nm
+expects its input to consist of:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+user name (UTF-8 string);
+.It
+user id (base64 blob).
+.El
+.Pp
+When verifying a credential,
+.Nm
+expects its input to consist of:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+credential format (UTF-8 string);
+.It
+authenticator data (base64 blob);
+.It
+credential id (base64 blob);
+.It
+attestation signature (base64 blob);
+.It
+attestation certificate (optional, base64 blob).
+.El
+.Pp
+UTF-8 strings passed to
+.Nm
+must not contain embedded newline or NUL characters.
+.Sh OUTPUT FORMAT
+The output of
+.Nm
+consists of base64 blobs, UTF-8 strings, and PEM-encoded public
+keys separated by newline characters ('\\n').
+.Pp
+Upon the successful generation of a credential,
+.Nm
+outputs:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+client data hash (base64 blob);
+.It
+relying party id (UTF-8 string);
+.It
+credential format (UTF-8 string);
+.It
+authenticator data (base64 blob);
+.It
+credential id (base64 blob);
+.It
+attestation signature (base64 blob);
+.It
+attestation certificate, if present (base64 blob).
+.It
+the credential's associated 32-byte symmetric key
+.Pq Dq largeBlobKey ,
+if present (base64 blob).
+.El
+.Pp
+Upon the successful verification of a credential,
+.Nm
+outputs:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+credential id (base64 blob);
+.It
+PEM-encoded credential key.
+.El
+.Sh EXAMPLES
+Create a new
+.Em es256
+credential on
+.Pa /dev/hidraw5 ,
+verify it, and save the id and the public key of the credential in
+.Em cred :
+.Pp
+.Dl $ echo credential challenge | openssl sha256 -binary | base64 > cred_param
+.Dl $ echo relying party >> cred_param
+.Dl $ echo user name >> cred_param
+.Dl $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param
+.Dl $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred
+.Sh SEE ALSO
+.Xr fido2-assert 1 ,
+.Xr fido2-token 1
+.Sh CAVEATS
+Please note that
+.Nm
+handles Basic Attestation and Self Attestation transparently.
+In the case of Basic Attestation, the validity of the authenticator's
+attestation certificate is
+.Em not
+verified.
diff --git a/man/fido2-token.1 b/man/fido2-token.1
new file mode 100644
index 0000000..65a228c
--- /dev/null
+++ b/man/fido2-token.1
@@ -0,0 +1,421 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: April 11 2022 $
+.Dt FIDO2-TOKEN 1
+.Os
+.Sh NAME
+.Nm fido2-token
+.Nd find and manage a FIDO2 authenticator
+.Sh SYNOPSIS
+.Nm
+.Fl C
+.Op Fl d
+.Ar device
+.Nm
+.Fl D
+.Op Fl d
+.Fl i
+.Ar cred_id
+.Ar device
+.Nm
+.Fl D
+.Fl b
+.Op Fl d
+.Fl k Ar key_path
+.Ar device
+.Nm
+.Fl D
+.Fl b
+.Op Fl d
+.Fl n Ar rp_id
+.Op Fl i Ar cred_id
+.Ar device
+.Nm
+.Fl D
+.Fl e
+.Op Fl d
+.Fl i
+.Ar template_id
+.Ar device
+.Nm
+.Fl D
+.Fl u
+.Op Fl d
+.Ar device
+.Nm
+.Fl G
+.Fl b
+.Op Fl d
+.Fl k Ar key_path
+.Ar blob_path
+.Ar device
+.Nm
+.Fl G
+.Fl b
+.Op Fl d
+.Fl n Ar rp_id
+.Op Fl i Ar cred_id
+.Ar blob_path
+.Ar device
+.Nm
+.Fl I
+.Op Fl cd
+.Op Fl k Ar rp_id Fl i Ar cred_id
+.Ar device
+.Nm
+.Fl L
+.Op Fl bder
+.Op Fl k Ar rp_id
+.Op device
+.Nm
+.Fl R
+.Op Fl d
+.Ar device
+.Nm
+.Fl S
+.Op Fl adefu
+.Ar device
+.Nm
+.Fl S
+.Op Fl d
+.Fl i Ar template_id
+.Fl n Ar template_name
+.Ar device
+.Nm
+.Fl S
+.Op Fl d
+.Fl l Ar pin_length
+.Ar device
+.Nm
+.Fl S
+.Fl b
+.Op Fl d
+.Fl k Ar key_path
+.Ar blob_path
+.Ar device
+.Nm
+.Fl S
+.Fl b
+.Op Fl d
+.Fl n Ar rp_id
+.Op Fl i Ar cred_id
+.Ar blob_path
+.Ar device
+.Nm
+.Fl S
+.Fl c
+.Op Fl d
+.Fl i Ar cred_id
+.Fl k Ar user_id
+.Fl n Ar name
+.Fl p Ar display_name
+.Ar device
+.Nm
+.Fl S
+.Fl m
+.Ar rp_id
+.Ar device
+.Nm
+.Fl V
+.Sh DESCRIPTION
+.Nm
+manages a FIDO2 authenticator.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl C Ar device
+Changes the PIN of
+.Ar device .
+The user will be prompted for the current and new PINs.
+.It Fl D Fl i Ar id Ar device
+Deletes the resident credential specified by
+.Ar id
+from
+.Ar device ,
+where
+.Ar id
+is the credential's base64-encoded id.
+The user will be prompted for the PIN.
+.It Fl D Fl b Fl k Ar key_path Ar device
+Deletes a
+.Dq largeBlob
+encrypted with
+.Ar key_path
+from
+.Ar device ,
+where
+.Ar key_path
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
+A PIN or equivalent user-verification gesture is required.
+.It Fl D Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar device
+Deletes a
+.Dq largeBlob
+corresponding to
+.Ar rp_id
+from
+.Ar device .
+If
+.Ar rp_id
+has multiple credentials enrolled on
+.Ar device ,
+the credential ID must be specified using
+.Fl i Ar cred_id ,
+where
+.Ar cred_id
+is a base64-encoded blob.
+A PIN or equivalent user-verification gesture is required.
+.It Fl D Fl e Fl i Ar id Ar device
+Deletes the biometric enrollment specified by
+.Ar id
+from
+.Ar device ,
+where
+.Ar id
+is the enrollment's template base64-encoded id.
+The user will be prompted for the PIN.
+.It Fl D Fl u Ar device
+Disables the CTAP 2.1
+.Dq user verification always
+feature on
+.Ar device .
+.It Fl G Fl b Fl k Ar key_path Ar blob_path Ar device
+Gets a CTAP 2.1
+.Dq largeBlob
+encrypted with
+.Ar key_path
+from
+.Ar device ,
+where
+.Ar key_path
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
+The blob is written to
+.Ar blob_path .
+A PIN or equivalent user-verification gesture is required.
+.It Fl G Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device
+Gets a CTAP 2.1
+.Dq largeBlob
+associated with
+.Ar rp_id
+from
+.Ar device .
+If
+.Ar rp_id
+has multiple credentials enrolled on
+.Ar device ,
+the credential ID must be specified using
+.Fl i Ar cred_id ,
+where
+.Ar cred_id
+is a base64-encoded blob.
+The blob is written to
+.Ar blob_path .
+A PIN or equivalent user-verification gesture is required.
+.It Fl I Ar device
+Retrieves information on
+.Ar device .
+.It Fl I Fl c Ar device
+Retrieves resident credential metadata from
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl I Fl k Ar rp_id Fl i Ar cred_id Ar device
+Prints the credential id (base64-encoded) and public key
+(PEM encoded) of the resident credential specified by
+.Ar rp_id
+and
+.Ar cred_id ,
+where
+.Ar rp_id
+is a UTF-8 relying party id, and
+.Ar cred_id
+is a base64-encoded credential id.
+The user will be prompted for the PIN.
+.It Fl L
+Produces a list of authenticators found by the operating system.
+.It Fl L Fl b Ar device
+Produces a list of CTAP 2.1
+.Dq largeBlobs
+on
+.Ar device .
+A PIN or equivalent user-verification gesture is required.
+.It Fl L Fl e Ar device
+Produces a list of biometric enrollments on
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl L Fl r Ar device
+Produces a list of relying parties with resident credentials on
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl L Fl k Ar rp_id Ar device
+Produces a list of resident credentials corresponding to
+relying party
+.Ar rp_id
+on
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl R
+Performs a reset on
+.Ar device .
+.Nm
+will NOT prompt for confirmation.
+.It Fl S
+Sets the PIN of
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl S Fl a Ar device
+Enables CTAP 2.1 Enterprise Attestation on
+.Ar device .
+.It Fl S Fl b Fl k Ar key_path Ar blob_path Ar device
+Sets a CTAP 2.1
+.Dq largeBlob
+encrypted with
+.Ar key_path
+on
+.Ar device ,
+where
+.Ar key_path
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
+The blob is read from
+.Fa blob_path .
+A PIN or equivalent user-verification gesture is required.
+.It Fl S Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device
+Sets a CTAP 2.1
+.Dq largeBlob
+associated with
+.Ar rp_id
+on
+.Ar device .
+The blob is read from
+.Fa blob_path .
+If
+.Ar rp_id
+has multiple credentials enrolled on
+.Ar device ,
+the credential ID must be specified using
+.Fl i Ar cred_id ,
+where
+.Ar cred_id
+is a base64-encoded blob.
+A PIN or equivalent user-verification gesture is required.
+.It Fl S Fl c Fl i Ar cred_id Fl k Ar user_id Fl n Ar name Fl p Ar display_name Ar device
+Sets the
+.Ar name
+and
+.Ar display_name
+attributes of the resident credential identified by
+.Ar cred_id
+and
+.Ar user_id ,
+where
+.Ar name
+and
+.Ar display_name
+are UTF-8 strings and
+.Ar cred_id
+and
+.Ar user_id
+are base64-encoded blobs.
+A PIN or equivalent user-verification gesture is required.
+.It Fl S Fl e Ar device
+Performs a new biometric enrollment on
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl S Fl e Fl i Ar template_id Fl n Ar template_name Ar device
+Sets the friendly name of the biometric enrollment specified by
+.Ar template_id
+to
+.Ar template_name
+on
+.Ar device ,
+where
+.Ar template_id
+is base64-encoded and
+.Ar template_name
+is a UTF-8 string.
+The user will be prompted for the PIN.
+.It Fl S Fl f Ar device
+Forces a PIN change on
+.Ar device .
+The user will be prompted for the PIN.
+.It Fl S Fl l Ar pin_length Ar device
+Sets the minimum PIN length of
+.Ar device
+to
+.Ar pin_length .
+The user will be prompted for the PIN.
+.It Fl S Fl m Ar rp_id Ar device
+Sets the list of relying party IDs that are allowed to retrieve
+the minimum PIN length of
+.Ar device .
+Multiple IDs may be specified, separated by commas.
+The user will be prompted for the PIN.
+.It Fl S Fl u Ar device
+Enables the CTAP 2.1
+.Dq user verification always
+feature on
+.Ar device .
+.It Fl V
+Prints version information.
+.It Fl d
+Causes
+.Nm
+to emit debugging output on
+.Em stderr .
+.El
+.Pp
+If a
+.Em tty
+is available,
+.Nm
+will use it to prompt for PINs.
+Otherwise,
+.Em stdin
+is used.
+.Pp
+.Nm
+exits 0 on success and 1 on error.
+.Sh SEE ALSO
+.Xr fido2-assert 1 ,
+.Xr fido2-cred 1
+.Sh CAVEATS
+The actual user-flow to perform a reset is outside the scope of the
+FIDO2 specification, and may therefore vary depending on the
+authenticator.
+Yubico authenticators do not allow resets after 5 seconds from
+power-up, and expect a reset to be confirmed by the user through
+touch within 30 seconds.
+.Pp
+An authenticator's path may contain spaces.
+.Pp
+Resident credentials are called
+.Dq discoverable credentials
+in CTAP 2.1.
+.Pp
+Whether the CTAP 2.1
+.Dq user verification always
+feature is activated or deactivated after an authenticator reset
+is vendor-specific.
diff --git a/man/fido_assert_allow_cred.3 b/man/fido_assert_allow_cred.3
new file mode 100644
index 0000000..6520137
--- /dev/null
+++ b/man/fido_assert_allow_cred.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: December 1 2022 $
+.Dt FIDO_ASSERT_ALLOW_CRED 3
+.Os
+.Sh NAME
+.Nm fido_assert_allow_cred ,
+.Nm fido_assert_empty_allow_list
+.Nd manage allow lists in a FIDO2 assertion
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_assert_allow_cred "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_empty_allow_list "fido_assert_t *assert"
+.Sh DESCRIPTION
+The
+.Fn fido_assert_allow_cred
+function adds
+.Fa ptr
+to the list of credentials allowed in
+.Fa assert ,
+where
+.Fa ptr
+points to a credential ID of
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+If
+.Fn fido_assert_allow_cred
+fails, the existing list of allowed credentials is preserved.
+.Pp
+For the format of a FIDO2 credential ID, please refer to the
+Web Authentication (webauthn) standard.
+.Pp
+The
+.Fn fido_assert_empty_allow_list
+function empties the list of credentials allowed in
+.Fa assert .
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_assert_allow_cred
+and
+.Fn fido_assert_empty_allow_list
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_assert_new 3 ,
+.Xr fido_assert_set_authdata 3 ,
+.Xr fido_dev_get_assert 3
diff --git a/man/fido_assert_new.3 b/man/fido_assert_new.3
new file mode 100644
index 0000000..fdc74a9
--- /dev/null
+++ b/man/fido_assert_new.3
@@ -0,0 +1,293 @@
+.\" Copyright (c) 2018-2023 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: June 19 2023 $
+.Dt FIDO_ASSERT_NEW 3
+.Os
+.Sh NAME
+.Nm fido_assert_new ,
+.Nm fido_assert_free ,
+.Nm fido_assert_count ,
+.Nm fido_assert_rp_id ,
+.Nm fido_assert_user_display_name ,
+.Nm fido_assert_user_icon ,
+.Nm fido_assert_user_name ,
+.Nm fido_assert_authdata_ptr ,
+.Nm fido_assert_authdata_raw_ptr ,
+.Nm fido_assert_blob_ptr ,
+.Nm fido_assert_clientdata_hash_ptr ,
+.Nm fido_assert_hmac_secret_ptr ,
+.Nm fido_assert_largeblob_key_ptr ,
+.Nm fido_assert_user_id_ptr ,
+.Nm fido_assert_sig_ptr ,
+.Nm fido_assert_id_ptr ,
+.Nm fido_assert_authdata_len ,
+.Nm fido_assert_authdata_raw_len ,
+.Nm fido_assert_blob_len ,
+.Nm fido_assert_clientdata_hash_len ,
+.Nm fido_assert_hmac_secret_len ,
+.Nm fido_assert_largeblob_key_len ,
+.Nm fido_assert_user_id_len ,
+.Nm fido_assert_sig_len ,
+.Nm fido_assert_id_len ,
+.Nm fido_assert_sigcount ,
+.Nm fido_assert_flags
+.Nd FIDO2 assertion API
+.Sh SYNOPSIS
+.In fido.h
+.Ft fido_assert_t *
+.Fn fido_assert_new "void"
+.Ft void
+.Fn fido_assert_free "fido_assert_t **assert_p"
+.Ft size_t
+.Fn fido_assert_count "const fido_assert_t *assert"
+.Ft const char *
+.Fn fido_assert_rp_id "const fido_assert_t *assert"
+.Ft const char *
+.Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx"
+.Ft const char *
+.Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx"
+.Ft const char *
+.Fn fido_assert_user_name "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_authdata_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_authdata_raw_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_clientdata_hash_ptr "const fido_assert_t *assert"
+.Ft const unsigned char *
+.Fn fido_assert_blob_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_hmac_secret_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_largeblob_key_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_id_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_authdata_raw_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_clientdata_hash_len "const fido_assert_t *assert"
+.Ft size_t
+.Fn fido_assert_blob_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_hmac_secret_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_largeblob_key_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_id_len "const fido_assert_t *assert" "size_t idx"
+.Ft uint32_t
+.Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx"
+.Ft uint8_t
+.Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx"
+.Sh DESCRIPTION
+A FIDO2 assertion is a collection of statements, each statement a
+map between a challenge, a credential, a signature, and ancillary
+attributes.
+In
+.Em libfido2 ,
+a FIDO2 assertion is abstracted by the
+.Vt fido_assert_t
+type.
+The functions described in this page allow a
+.Vt fido_assert_t
+type to be allocated, deallocated, and inspected.
+For other operations on
+.Vt fido_assert_t ,
+please refer to
+.Xr fido_assert_set_authdata 3 ,
+.Xr fido_assert_allow_cred 3 ,
+.Xr fido_assert_verify 3 ,
+and
+.Xr fido_dev_get_assert 3 .
+.Pp
+The
+.Fn fido_assert_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_assert_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_assert_free
+function releases the memory backing
+.Fa *assert_p ,
+where
+.Fa *assert_p
+must have been previously allocated by
+.Fn fido_assert_new .
+On return,
+.Fa *assert_p
+is set to NULL.
+Either
+.Fa assert_p
+or
+.Fa *assert_p
+may be NULL, in which case
+.Fn fido_assert_free
+is a NOP.
+.Pp
+The
+.Fn fido_assert_count
+function returns the number of statements in
+.Fa assert .
+.Pp
+The
+.Fn fido_assert_rp_id
+function returns a pointer to a NUL-terminated string holding the
+relying party ID of
+.Fa assert .
+.Pp
+The
+.Fn fido_assert_user_display_name ,
+.Fn fido_assert_user_icon ,
+and
+.Fn fido_assert_user_name ,
+functions return pointers to the user display name, icon, and
+name attributes of statement
+.Fa idx
+in
+.Fa assert .
+If not NULL, the values returned by these functions point to
+NUL-terminated UTF-8 strings.
+The user display name, icon, and name attributes will typically
+only be returned by the authenticator if user verification was
+performed by the authenticator and multiple resident/discoverable
+credentials were involved in the assertion.
+.Pp
+The
+.Fn fido_assert_authdata_ptr ,
+.Fn fido_assert_authdata_raw_ptr ,
+.Fn fido_assert_clientdata_hash_ptr ,
+.Fn fido_assert_id_ptr ,
+.Fn fido_assert_user_id_ptr ,
+.Fn fido_assert_sig_ptr ,
+.Fn fido_assert_sigcount ,
+and
+.Fn fido_assert_flags
+functions return pointers to the CBOR-encoded and raw authenticator data,
+client data hash, credential ID, user ID, signature, signature
+count, and authenticator data flags of statement
+.Fa idx
+in
+.Fa assert .
+.Pp
+The
+.Fn fido_assert_hmac_secret_ptr
+function returns a pointer to the hmac-secret attribute of statement
+.Fa idx
+in
+.Fa assert .
+The HMAC Secret Extension
+.Pq hmac-secret
+is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
+.Pp
+The
+.Fn fido_assert_blob_ptr
+and
+.Fn fido_assert_largeblob_key_ptr
+functions return pointers to the
+.Dq credBlob
+and
+.Dq largeBlobKey
+attributes of statement
+.Fa idx
+in
+.Fa assert .
+Credential Blob
+.Pq credBlob
+and
+Large Blob Key
+.Pq largeBlobKey
+are CTAP 2.1 extensions.
+.Pp
+The
+.Fn fido_assert_authdata_len ,
+.Fn fido_assert_authdata_raw_len ,
+.Fn fido_assert_clientdata_hash_len ,
+.Fn fido_assert_id_len ,
+.Fn fido_assert_user_id_len ,
+.Fn fido_assert_sig_len ,
+.Fn fido_assert_hmac_secret_len ,
+.Fn fido_assert_blob_len ,
+and
+.Fn fido_assert_largeblob_key_len
+functions return the length of a given attribute.
+.Pp
+Please note that the first statement in
+.Fa assert
+has an
+.Fa idx
+(index) value of 0.
+.Pp
+The authenticator data and signature parts of an assertion
+statement are typically passed to a FIDO2 server for verification.
+.Sh RETURN VALUES
+The authenticator data returned by
+.Fn fido_assert_authdata_ptr
+is a CBOR-encoded byte string, as obtained from the authenticator.
+.Pp
+The
+.Fn fido_assert_rp_id ,
+.Fn fido_assert_user_display_name ,
+.Fn fido_assert_user_icon ,
+.Fn fido_assert_user_name ,
+.Fn fido_assert_authdata_ptr ,
+.Fn fido_assert_clientdata_hash_ptr ,
+.Fn fido_assert_id_ptr ,
+.Fn fido_assert_user_id_ptr ,
+.Fn fido_assert_sig_ptr ,
+.Fn fido_assert_hmac_secret_ptr ,
+.Fn fido_assert_blob_ptr ,
+and
+.Fn fido_assert_largeblob_key_ptr
+functions may return NULL if the respective field in
+.Fa assert
+is not set.
+If not NULL, returned pointers are guaranteed to exist until any API
+function that takes
+.Fa assert
+without the
+.Em const
+qualifier is invoked.
+.Sh SEE ALSO
+.Xr fido_assert_allow_cred 3 ,
+.Xr fido_assert_set_authdata 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_dev_get_assert 3 ,
+.Xr fido_dev_largeblob_get 3
diff --git a/man/fido_assert_set_authdata.3 b/man/fido_assert_set_authdata.3
new file mode 100644
index 0000000..503e2bf
--- /dev/null
+++ b/man/fido_assert_set_authdata.3
@@ -0,0 +1,314 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: April 8 2023 $
+.Dt FIDO_ASSERT_SET_AUTHDATA 3
+.Os
+.Sh NAME
+.Nm fido_assert_set_authdata ,
+.Nm fido_assert_set_authdata_raw ,
+.Nm fido_assert_set_clientdata ,
+.Nm fido_assert_set_clientdata_hash ,
+.Nm fido_assert_set_count ,
+.Nm fido_assert_set_extensions ,
+.Nm fido_assert_set_hmac_salt ,
+.Nm fido_assert_set_hmac_secret ,
+.Nm fido_assert_set_up ,
+.Nm fido_assert_set_uv ,
+.Nm fido_assert_set_rp ,
+.Nm fido_assert_set_sig ,
+.Nm fido_assert_set_winhello_appid
+.Nd set parameters of a FIDO2 assertion
+.Sh SYNOPSIS
+.In fido.h
+.Bd -literal
+typedef enum {
+ FIDO_OPT_OMIT = 0, /* use authenticator's default */
+ FIDO_OPT_FALSE, /* explicitly set option to false */
+ FIDO_OPT_TRUE, /* explicitly set option to true */
+} fido_opt_t;
+.Ed
+.Ft int
+.Fn fido_assert_set_authdata "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_authdata_raw "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_clientdata "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_clientdata_hash "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_count "fido_assert_t *assert" "size_t n"
+.Ft int
+.Fn fido_assert_set_extensions "fido_assert_t *assert" "int flags"
+.Ft int
+.Fn fido_assert_set_hmac_salt "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_hmac_secret "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_up "fido_assert_t *assert" "fido_opt_t up"
+.Ft int
+.Fn fido_assert_set_uv "fido_assert_t *assert" "fido_opt_t uv"
+.Ft int
+.Fn fido_assert_set_rp "fido_assert_t *assert" "const char *id"
+.Ft int
+.Fn fido_assert_set_sig "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_assert_set_winhello_appid "fido_assert_t *assert" "const char *id"
+.Sh DESCRIPTION
+The
+.Nm
+set of functions define the various parameters of a FIDO2
+assertion, allowing a
+.Fa fido_assert_t
+type to be prepared for a subsequent call to
+.Xr fido_dev_get_assert 3
+or
+.Xr fido_assert_verify 3 .
+For the complete specification of a FIDO2 assertion and the format
+of its constituent parts, please refer to the Web Authentication
+(webauthn) standard.
+.Pp
+The
+.Fn fido_assert_set_count
+function sets the number of assertion statements in
+.Fa assert
+to
+.Fa n .
+.Pp
+The
+.Fn fido_assert_set_authdata
+and
+.Fn fido_assert_set_sig
+functions set the authenticator data and signature parts of the
+statement with index
+.Fa idx
+of
+.Fa assert
+to
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+Please note that the first assertion statement of
+.Fa assert
+has an
+.Fa idx
+of
+.Em 0 .
+The authenticator data passed to
+.Fn fido_assert_set_authdata
+must be a CBOR-encoded byte string, as obtained from
+.Fn fido_assert_authdata_ptr .
+Alternatively, a raw binary blob may be passed to
+.Fn fido_assert_set_authdata_raw .
+.Pp
+The
+.Fn fido_assert_set_clientdata_hash
+function sets the client data hash of
+.Fa assert
+to
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+.Pp
+The
+.Fn fido_assert_set_clientdata
+function allows an application to set the client data hash of
+.Fa assert
+by specifying the assertion's unhashed client data.
+This is required by Windows Hello, which calculates the client data
+hash internally.
+For compatibility with Windows Hello, applications should use
+.Fn fido_assert_set_clientdata
+instead of
+.Fn fido_assert_set_clientdata_hash .
+.Pp
+The
+.Fn fido_assert_set_rp
+function sets the relying party
+.Fa id
+of
+.Fa assert ,
+where
+.Fa id
+is a NUL-terminated UTF-8 string.
+The content of
+.Fa id
+is copied, and no references to the passed pointer are kept.
+.Pp
+The
+.Fn fido_assert_set_extensions
+function sets the extensions of
+.Fa assert
+to the bitmask
+.Fa flags .
+At the moment, only the
+.Dv FIDO_EXT_CRED_BLOB ,
+.Dv FIDO_EXT_HMAC_SECRET ,
+and
+.Dv FIDO_EXT_LARGEBLOB_KEY
+extensions are supported.
+If
+.Fa flags
+is zero, the extensions of
+.Fa assert
+are cleared.
+.Pp
+The
+.Fn fido_assert_set_hmac_salt
+and
+.Fn fido_assert_set_hmac_secret
+functions set the hmac-salt and hmac-secret parts of
+.Fa assert
+to
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+The HMAC Secret
+.Pq hmac-secret
+Extension is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
+The
+.Fn fido_assert_set_hmac_secret
+function is normally only useful when writing tests.
+.Pp
+The
+.Fn fido_assert_set_up
+and
+.Fn fido_assert_set_uv
+functions set the
+.Fa up
+(user presence) and
+.Fa uv
+(user verification)
+attributes of
+.Fa assert .
+Both are
+.Dv FIDO_OPT_OMIT
+by default, allowing the authenticator to use its default settings.
+.Pp
+The
+.Fn fido_assert_set_winhello_appid
+function sets the U2F application
+.Fa id
+.Pq Dq U2F AppID
+of
+.Fa assert ,
+where
+.Fa id
+is a NUL-terminated UTF-8 string.
+The content of
+.Fa id
+is copied, and no references to the passed pointer are kept.
+The
+.Fn fido_assert_set_winhello_appid
+function is a no-op unless
+.Fa assert
+is passed to
+.Xr fido_dev_get_assert 3
+with a device
+.Fa dev
+on which
+.Xr fido_dev_is_winhello 3
+holds true.
+In this case,
+.Em libfido2
+will instruct Windows Hello to try the assertion twice,
+first with the
+.Fa id
+passed to
+.Fn fido_assert_set_rp ,
+and a second time with the
+.Fa id
+passed to
+.Fn fido_assert_set_winhello_appid .
+If the second assertion succeeds,
+.Xr fido_assert_rp_id 3
+will point to the U2F AppID once
+.Xr fido_dev_get_assert 3
+completes.
+This mechanism exists in Windows Hello to ensure U2F backwards
+compatibility without the application inadvertently prompting the
+user twice.
+Note that
+.Fn fido_assert_set_winhello_appid
+is not needed on platforms offering CTAP primitives, since the
+authenticator can be silently probed for the existence of U2F
+credentials.
+.Pp
+Use of the
+.Nm
+set of functions may happen in two distinct situations:
+when asking a FIDO2 device to produce a series of assertion
+statements, prior to
+.Xr fido_dev_get_assert 3
+(i.e, in the context of a FIDO2 client), or when verifying assertion
+statements using
+.Xr fido_assert_verify 3
+(i.e, in the context of a FIDO2 server).
+.Pp
+For a complete description of the generation of a FIDO2 assertion
+and its verification, please refer to the FIDO2 specification.
+An example of how to use the
+.Nm
+set of functions can be found in the
+.Pa examples/assert.c
+file shipped with
+.Em libfido2 .
+.Sh RETURN VALUES
+The
+.Nm
+functions return
+.Dv FIDO_OK
+on success.
+The error codes returned by the
+.Nm
+set of functions are defined in
+.In fido/err.h .
+.Sh SEE ALSO
+.Xr fido_assert_allow_cred 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_dev_get_assert 3 ,
+.Xr fido_dev_is_winhello 3
diff --git a/man/fido_assert_verify.3 b/man/fido_assert_verify.3
new file mode 100644
index 0000000..1b79448
--- /dev/null
+++ b/man/fido_assert_verify.3
@@ -0,0 +1,104 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt FIDO_ASSERT_VERIFY 3
+.Os
+.Sh NAME
+.Nm fido_assert_verify
+.Nd verifies the signature of a FIDO2 assertion statement
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_assert_verify "const fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk"
+.Sh DESCRIPTION
+The
+.Fn fido_assert_verify
+function verifies whether the signature contained in statement index
+.Fa idx
+of
+.Fa assert
+matches the parameters of the assertion.
+Before using
+.Fn fido_assert_verify
+in a sensitive context, the reader is strongly encouraged to make
+herself familiar with the FIDO2 assertion statement process
+as defined in the Web Authentication (webauthn) standard.
+.Pp
+A brief description follows:
+.Pp
+The
+.Fn fido_assert_verify
+function verifies whether the client data hash, relying party ID,
+user presence and user verification attributes of
+.Fa assert
+have been attested by the holder of the private counterpart of
+the public key
+.Fa pk
+of COSE type
+.Fa cose_alg ,
+where
+.Fa cose_alg
+is
+.Dv COSE_ES256 ,
+.Dv COSE_ES384 ,
+.Dv COSE_RS256 ,
+or
+.Dv COSE_EDDSA ,
+and
+.Fa pk
+points to a
+.Vt es256_pk_t ,
+.Vt es384_pk_t ,
+.Vt rs256_pk_t ,
+or
+.Vt eddsa_pk_t
+type accordingly.
+.Pp
+Please note that the first statement in
+.Fa assert
+has an
+.Fa idx
+of 0.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_assert_verify
+are defined in
+.In fido/err.h .
+If
+statement
+.Fa idx
+of
+.Fa assert
+passes verification with
+.Fa pk ,
+then
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_assert_new 3 ,
+.Xr fido_assert_set_authdata 3
diff --git a/man/fido_bio_dev_get_info.3 b/man/fido_bio_dev_get_info.3
new file mode 100644
index 0000000..b8fc104
--- /dev/null
+++ b/man/fido_bio_dev_get_info.3
@@ -0,0 +1,145 @@
+.\" Copyright (c) 2019 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: September 13 2019 $
+.Dt FIDO_BIO_DEV_GET_INFO 3
+.Os
+.Sh NAME
+.Nm fido_bio_dev_get_info ,
+.Nm fido_bio_dev_enroll_begin ,
+.Nm fido_bio_dev_enroll_continue ,
+.Nm fido_bio_dev_enroll_cancel ,
+.Nm fido_bio_dev_enroll_remove ,
+.Nm fido_bio_dev_get_template_array ,
+.Nm fido_bio_dev_set_template_name
+.Nd FIDO2 biometric authenticator API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/bio.h
+.Ft int
+.Fn fido_bio_dev_get_info "fido_dev_t *dev" "fido_bio_info_t *info"
+.Ft int
+.Fn fido_bio_dev_enroll_begin "fido_dev_t *dev" "fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" "const char *pin"
+.Ft int
+.Fn fido_bio_dev_enroll_continue "fido_dev_t *dev" "const fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms"
+.Ft int
+.Fn fido_bio_dev_enroll_cancel "fido_dev_t *dev"
+.Ft int
+.Fn fido_bio_dev_enroll_remove "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin"
+.Ft int
+.Fn fido_bio_dev_get_template_array "fido_dev_t *dev" "fido_bio_template_array_t *template_array" "const char *pin"
+.Ft int
+.Fn fido_bio_dev_set_template_name "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin"
+.Sh DESCRIPTION
+The functions described in this page allow biometric
+templates on a FIDO2 authenticator to be listed, created,
+removed, and customised.
+Please note that not all FIDO2 authenticators support biometric
+enrollment.
+For a description of the types involved, please refer to
+.Xr fido_bio_info_new 3 ,
+.Xr fido_bio_enroll_new 3 ,
+and
+.Xr fido_bio_template 3 .
+.Pp
+The
+.Fn fido_bio_dev_get_info
+function populates
+.Fa info
+with sensor information from
+.Fa dev .
+.Pp
+The
+.Fn fido_bio_dev_enroll_begin
+function initiates a biometric enrollment on
+.Fa dev ,
+instructing the authenticator to wait
+.Fa timeout_ms
+milliseconds.
+On success,
+.Fa template
+and
+.Fa enroll
+will be populated with the newly created template's
+information and enrollment status, respectively.
+.Pp
+The
+.Fn fido_bio_dev_enroll_continue
+function continues an ongoing enrollment on
+.Fa dev ,
+instructing the authenticator to wait
+.Fa timeout_ms
+milliseconds.
+On success,
+.Fa enroll
+will be updated to reflect the status of the biometric
+enrollment.
+.Pp
+The
+.Fn fido_bio_dev_enroll_cancel
+function cancels an ongoing enrollment on
+.Fa dev .
+.Pp
+The
+.Fn fido_bio_dev_enroll_remove
+function removes
+.Fa template
+from
+.Fa dev .
+.Pp
+The
+.Fn fido_bio_dev_get_template_array
+function populates
+.Fa template_array
+with the templates currently enrolled on
+.Fa dev .
+.Pp
+The
+.Fn fido_bio_dev_set_template_name
+function sets the friendly name of
+.Fa template
+on
+.Fa dev .
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_bio_dev_get_info ,
+.Fn fido_bio_dev_enroll_begin ,
+.Fn fido_bio_dev_enroll_continue ,
+.Fn fido_bio_dev_enroll_cancel ,
+.Fn fido_bio_dev_enroll_remove ,
+.Fn fido_bio_dev_get_template_array ,
+and
+.Fn fido_bio_dev_set_template_name
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_bio_enroll_new 3 ,
+.Xr fido_bio_info_new 3 ,
+.Xr fido_bio_template 3
diff --git a/man/fido_bio_enroll_new.3 b/man/fido_bio_enroll_new.3
new file mode 100644
index 0000000..536ba9a
--- /dev/null
+++ b/man/fido_bio_enroll_new.3
@@ -0,0 +1,118 @@
+.\" Copyright (c) 2019 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: September 13 2019 $
+.Dt FIDO_BIO_ENROLL_NEW 3
+.Os
+.Sh NAME
+.Nm fido_bio_enroll_new ,
+.Nm fido_bio_enroll_free ,
+.Nm fido_bio_enroll_last_status ,
+.Nm fido_bio_enroll_remaining_samples
+.Nd FIDO2 biometric enrollment API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/bio.h
+.Bd -literal
+#define FIDO_BIO_ENROLL_FP_GOOD 0x00
+#define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01
+#define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02
+#define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03
+#define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04
+#define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05
+#define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06
+#define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07
+#define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08
+#define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09
+#define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a
+#define FIDO_BIO_ENROLL_FP_EXISTS 0x0b
+#define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c
+#define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d
+#define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e
+.Ed
+.Ft fido_bio_enroll_t *
+.Fn fido_bio_enroll_new "void"
+.Ft void
+.Fn fido_bio_enroll_free "fido_bio_enroll_t **enroll_p"
+.Ft uint8_t
+.Fn fido_bio_enroll_last_status "const fido_bio_enroll_t *enroll"
+.Ft uint8_t
+.Fn fido_bio_enroll_remaining_samples "const fido_bio_enroll_t *enroll"
+.Sh DESCRIPTION
+Ongoing FIDO2 biometric enrollments are abstracted in
+.Em libfido2
+by the
+.Vt fido_bio_enroll_t
+type.
+.Pp
+The functions described in this page allow a
+.Vt fido_bio_enroll_t
+type to be allocated, deallocated, and inspected.
+For device operations on
+.Vt fido_bio_enroll_t ,
+please refer to
+.Xr fido_bio_dev_get_info 3 .
+.Pp
+The
+.Fn fido_bio_enroll_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_bio_enroll_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_bio_enroll_free
+function releases the memory backing
+.Fa *enroll_p ,
+where
+.Fa *enroll_p
+must have been previously allocated by
+.Fn fido_bio_enroll_new .
+On return,
+.Fa *enroll_p
+is set to NULL.
+Either
+.Fa enroll_p
+or
+.Fa *enroll_p
+may be NULL, in which case
+.Fn fido_bio_enroll_free
+is a NOP.
+.Pp
+The
+.Fn fido_bio_enroll_last_status
+function returns the enrollment status of
+.Fa enroll .
+.Pp
+The
+.Fn fido_bio_enroll_remaining_samples
+function returns the number of samples left for
+.Fa enroll
+to complete.
+.Sh SEE ALSO
+.Xr fido_bio_dev_get_info 3 ,
+.Xr fido_bio_template 3
diff --git a/man/fido_bio_info_new.3 b/man/fido_bio_info_new.3
new file mode 100644
index 0000000..4134306
--- /dev/null
+++ b/man/fido_bio_info_new.3
@@ -0,0 +1,104 @@
+.\" Copyright (c) 2019 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: September 13 2019 $
+.Dt FIDO_BIO_INFO_NEW 3
+.Os
+.Sh NAME
+.Nm fido_bio_info_new ,
+.Nm fido_bio_info_free ,
+.Nm fido_bio_info_type ,
+.Nm fido_bio_info_max_samples
+.Nd FIDO2 biometric sensor information API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/bio.h
+.Ft fido_bio_info_t *
+.Fn fido_bio_info_new "void"
+.Ft void
+.Fn fido_bio_info_free "fido_bio_info_t **info_p"
+.Ft uint8_t
+.Fn fido_bio_info_type "const fido_bio_info_t *info"
+.Ft uint8_t
+.Fn fido_bio_info_max_samples "const fido_bio_info_t *info"
+.Sh DESCRIPTION
+Biometric sensor metadata is abstracted in
+.Em libfido2
+by the
+.Vt fido_bio_info_t
+type.
+.Pp
+The functions described in this page allow a
+.Vt fido_bio_info_t
+type to be allocated, deallocated, and inspected.
+For device operations on
+.Vt fido_bio_info_t ,
+please refer to
+.Xr fido_bio_dev_get_info 3 .
+.Pp
+The
+.Fn fido_bio_info_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_bio_info_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_bio_info_free
+function releases the memory backing
+.Fa *info_p ,
+where
+.Fa *info_p
+must have been previously allocated by
+.Fn fido_bio_info_new .
+On return,
+.Fa *info_p
+is set to NULL.
+Either
+.Fa info_p
+or
+.Fa *info_p
+may be NULL, in which case
+.Fn fido_bio_info_free
+is a NOP.
+.Pp
+The
+.Fn fido_bio_info_type
+function returns the fingerprint sensor type, which is
+.Dv 1
+for touch sensors, and
+.Dv 2
+for swipe sensors.
+.Pp
+The
+.Fn fido_bio_info_max_samples
+function returns the maximum number of successful samples
+required for enrollment.
+.Sh SEE ALSO
+.Xr fido_bio_dev_get_info 3 ,
+.Xr fido_bio_enroll_new 3 ,
+.Xr fido_bio_template 3
diff --git a/man/fido_bio_template.3 b/man/fido_bio_template.3
new file mode 100644
index 0000000..a8ff8bc
--- /dev/null
+++ b/man/fido_bio_template.3
@@ -0,0 +1,202 @@
+.\" Copyright (c) 2019 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: September 13 2019 $
+.Dt FIDO_BIO_TEMPLATE 3
+.Os
+.Sh NAME
+.Nm fido_bio_template ,
+.Nm fido_bio_template_array_count ,
+.Nm fido_bio_template_array_free ,
+.Nm fido_bio_template_array_new ,
+.Nm fido_bio_template_free ,
+.Nm fido_bio_template_id_len ,
+.Nm fido_bio_template_id_ptr ,
+.Nm fido_bio_template_name ,
+.Nm fido_bio_template_new ,
+.Nm fido_bio_template_set_id ,
+.Nm fido_bio_template_set_name
+.Nd FIDO2 biometric template API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/bio.h
+.Ft fido_bio_template_t *
+.Fn fido_bio_template_new "void"
+.Ft void
+.Fn fido_bio_template_free "fido_bio_template_t **template_p"
+.Ft const char *
+.Fn fido_bio_template_name "const fido_bio_template_t *template"
+.Ft const unsigned char *
+.Fn fido_bio_template_id_ptr "const fido_bio_template_t *template"
+.Ft size_t
+.Fn fido_bio_template_id_len "const fido_bio_template_t *template"
+.Ft int
+.Fn fido_bio_template_set_id "fido_bio_template_t *template" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_bio_template_set_name "fido_bio_template_t *template" "const char *name"
+.Ft fido_bio_template_array_t *
+.Fn fido_bio_template_array_new "void"
+.Ft void
+.Fn fido_bio_template_array_free "fido_bio_template_array_t **array_p"
+.Ft size_t
+.Fn fido_bio_template_array_count "const fido_bio_template_array_t *array"
+.Ft const fido_bio_template_t *
+.Fn fido_bio_template "const fido_bio_template_array_t *array" "size_t idx"
+.Sh DESCRIPTION
+Existing FIDO2 biometric enrollments are abstracted in
+.Em libfido2
+by the
+.Vt fido_bio_template_t
+and
+.Vt fido_bio_template_array_t
+types.
+.Pp
+The functions described in this page allow a
+.Vt fido_bio_template_t
+type to be allocated, deallocated, changed, and inspected,
+and a
+.Vt fido_bio_template_array_t
+type to be allocated, deallocated, and inspected.
+For device operations on
+.Vt fido_bio_template_t
+and
+.Vt fido_bio_template_array_t ,
+please refer to
+.Xr fido_bio_dev_get_info 3 .
+.Pp
+The
+.Fn fido_bio_template_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_bio_template_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_bio_template_free
+function releases the memory backing
+.Fa *template_p ,
+where
+.Fa *template_p
+must have been previously allocated by
+.Fn fido_bio_template_new .
+On return,
+.Fa *template_p
+is set to NULL.
+Either
+.Fa template_p
+or
+.Fa *template_p
+may be NULL, in which case
+.Fn fido_bio_template_free
+is a NOP.
+.Pp
+The
+.Fn fido_bio_template_name
+function returns a pointer to a NUL-terminated string containing
+the friendly name of
+.Fa template ,
+or NULL if
+.Fa template
+does not have a friendly name set.
+.Pp
+The
+.Fn fido_bio_template_id_ptr
+function returns a pointer to the template id of
+.Fa template ,
+or NULL if
+.Fa template
+does not have an id.
+The corresponding length can be obtained by
+.Fn fido_bio_template_id_len .
+.Pp
+The
+.Fn fido_bio_template_set_name
+function sets the friendly name of
+.Fa template
+to
+.Fa name .
+If
+.Fa name
+is NULL, the friendly name of
+.Fa template
+is unset.
+.Pp
+The
+.Fn fido_bio_template_array_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_bio_template_array_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_bio_template_array_free
+function releases the memory backing
+.Fa *array_p ,
+where
+.Fa *array_p
+must have been previously allocated by
+.Fn fido_bio_template_array_new .
+On return,
+.Fa *array_p
+is set to NULL.
+Either
+.Fa array_p
+or
+.Fa *array_p
+may be NULL, in which case
+.Fn fido_bio_template_array_free
+is a NOP.
+.Pp
+The
+.Fn fido_bio_template_array_count
+function returns the number of templates in
+.Fa array .
+.Pp
+The
+.Fn fido_bio_template
+function returns a pointer to the template at index
+.Fa idx
+in
+.Fa array .
+Please note that the first template in
+.Fa array
+has an
+.Fa idx
+(index) value of 0.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_bio_template_set_id
+and
+.Fn fido_bio_template_set_name
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_bio_dev_get_info 3 ,
+.Xr fido_bio_enroll_new 3
diff --git a/man/fido_cbor_info_new.3 b/man/fido_cbor_info_new.3
new file mode 100644
index 0000000..a8168c0
--- /dev/null
+++ b/man/fido_cbor_info_new.3
@@ -0,0 +1,389 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: April 22 2022 $
+.Dt FIDO_CBOR_INFO_NEW 3
+.Os
+.Sh NAME
+.Nm fido_cbor_info_new ,
+.Nm fido_cbor_info_free ,
+.Nm fido_dev_get_cbor_info ,
+.Nm fido_cbor_info_aaguid_ptr ,
+.Nm fido_cbor_info_extensions_ptr ,
+.Nm fido_cbor_info_protocols_ptr ,
+.Nm fido_cbor_info_transports_ptr ,
+.Nm fido_cbor_info_versions_ptr ,
+.Nm fido_cbor_info_options_name_ptr ,
+.Nm fido_cbor_info_options_value_ptr ,
+.Nm fido_cbor_info_algorithm_type ,
+.Nm fido_cbor_info_algorithm_cose ,
+.Nm fido_cbor_info_algorithm_count ,
+.Nm fido_cbor_info_certs_name_ptr ,
+.Nm fido_cbor_info_certs_value_ptr ,
+.Nm fido_cbor_info_certs_len ,
+.Nm fido_cbor_info_aaguid_len ,
+.Nm fido_cbor_info_extensions_len ,
+.Nm fido_cbor_info_protocols_len ,
+.Nm fido_cbor_info_transports_len ,
+.Nm fido_cbor_info_versions_len ,
+.Nm fido_cbor_info_options_len ,
+.Nm fido_cbor_info_maxmsgsiz ,
+.Nm fido_cbor_info_maxcredbloblen ,
+.Nm fido_cbor_info_maxcredcntlst ,
+.Nm fido_cbor_info_maxcredidlen ,
+.Nm fido_cbor_info_maxlargeblob ,
+.Nm fido_cbor_info_maxrpid_minpinlen ,
+.Nm fido_cbor_info_minpinlen ,
+.Nm fido_cbor_info_fwversion ,
+.Nm fido_cbor_info_uv_attempts ,
+.Nm fido_cbor_info_uv_modality ,
+.Nm fido_cbor_info_rk_remaining ,
+.Nm fido_cbor_info_new_pin_required
+.Nd FIDO2 CBOR Info API
+.Sh SYNOPSIS
+.In fido.h
+.Ft fido_cbor_info_t *
+.Fn fido_cbor_info_new "void"
+.Ft void
+.Fn fido_cbor_info_free "fido_cbor_info_t **ci_p"
+.Ft int
+.Fn fido_dev_get_cbor_info "fido_dev_t *dev" "fido_cbor_info_t *ci"
+.Ft const unsigned char *
+.Fn fido_cbor_info_aaguid_ptr "const fido_cbor_info_t *ci"
+.Ft char **
+.Fn fido_cbor_info_extensions_ptr "const fido_cbor_info_t *ci"
+.Ft const uint8_t *
+.Fn fido_cbor_info_protocols_ptr "const fido_cbor_info_t *ci"
+.Ft char **
+.Fn fido_cbor_info_transports_ptr "const fido_cbor_info_t *ci"
+.Ft char **
+.Fn fido_cbor_info_versions_ptr "const fido_cbor_info_t *ci"
+.Ft char **
+.Fn fido_cbor_info_options_name_ptr "const fido_cbor_info_t *ci"
+.Ft const bool *
+.Fn fido_cbor_info_options_value_ptr "const fido_cbor_info_t *ci"
+.Ft const char *
+.Fn fido_cbor_info_algorithm_type "const fido_cbor_info_t *ci" "size_t idx"
+.Ft int
+.Fn fido_cbor_info_algorithm_cose "const fido_cbor_info_t *ci" "size_t idx"
+.Ft size_t
+.Fn fido_cbor_info_algorithm_count "const fido_cbor_info_t *ci"
+.Ft char **
+.Fn fido_cbor_info_certs_name_ptr "const fido_cbor_info_t *ci"
+.Ft const uint64_t *
+.Fn fido_cbor_info_certs_value_ptr "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_certs_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_aaguid_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_extensions_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_protocols_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_transports_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_versions_len "const fido_cbor_info_t *ci"
+.Ft size_t
+.Fn fido_cbor_info_options_len "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxcredbloblen "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxcredcntlst "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxlargeblob "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxrpid_minpinlen "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_minpinlen "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_uv_attempts "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_uv_modality "const fido_cbor_info_t *ci"
+.Ft int64_t
+.Fn fido_cbor_info_rk_remaining "const fido_cbor_info_t *ci"
+.Ft bool
+.Fn fido_cbor_info_new_pin_required "const fido_cbor_info_t *ci"
+.Sh DESCRIPTION
+The
+.Fn fido_cbor_info_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_cbor_info_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_cbor_info_free
+function releases the memory backing
+.Fa *ci_p ,
+where
+.Fa *ci_p
+must have been previously allocated by
+.Fn fido_cbor_info_new .
+On return,
+.Fa *ci_p
+is set to NULL.
+Either
+.Fa ci_p
+or
+.Fa *ci_p
+may be NULL, in which case
+.Fn fido_cbor_info_free
+is a NOP.
+.Pp
+The
+.Fn fido_dev_get_cbor_info
+function transmits a
+.Dv CTAP_CBOR_GETINFO
+command to
+.Fa dev
+and fills
+.Fa ci
+with attributes retrieved from the command's response.
+The
+.Fn fido_dev_get_cbor_info
+function may block.
+.Pp
+The
+.Fn fido_cbor_info_aaguid_ptr ,
+.Fn fido_cbor_info_extensions_ptr ,
+.Fn fido_cbor_info_protocols_ptr ,
+.Fn fido_cbor_info_transports_ptr ,
+and
+.Fn fido_cbor_info_versions_ptr
+functions return pointers to the authenticator attestation GUID,
+supported extensions, PIN protocol, transports, and CTAP version
+strings of
+.Fa ci .
+The corresponding length of a given attribute can be
+obtained by
+.Fn fido_cbor_info_aaguid_len ,
+.Fn fido_cbor_info_extensions_len ,
+.Fn fido_cbor_info_protocols_len ,
+.Fn fido_cbor_info_transports_len ,
+or
+.Fn fido_cbor_info_versions_len .
+.Pp
+The
+.Fn fido_cbor_info_options_name_ptr
+and
+.Fn fido_cbor_info_options_value_ptr
+functions return pointers to the array of option names and their
+respective values
+in
+.Fa ci .
+The length of the options array is returned by
+.Fn fido_cbor_info_options_len .
+.Pp
+The
+.Fn fido_cbor_info_algorithm_count
+function returns the number of supported algorithms in
+.Fa ci .
+The
+.Fn fido_cbor_info_algorithm_cose
+function returns the COSE identifier of algorithm
+.Fa idx
+in
+.Fa ci ,
+or 0 if the COSE identifier is unknown or unset.
+The
+.Fn fido_cbor_info_algorithm_type
+function returns the type of algorithm
+.Fa idx
+in
+.Fa ci ,
+or NULL if the type is unset.
+Please note that the first algorithm in
+.Fa ci
+has an
+.Fa idx
+(index) value of 0.
+.Pp
+The
+.Fn fido_cbor_info_certs_name_ptr
+and
+.Fn fido_cbor_info_certs_value_ptr
+functions return pointers to the array of certification names and their
+respective values
+in
+.Fa ci .
+The length of the certifications array is returned by
+.Fn fido_cbor_info_certs_len .
+.Pp
+The
+.Fn fido_cbor_info_maxmsgsiz
+function returns the maximum message size attribute of
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxcredbloblen
+function returns the maximum
+.Dq credBlob
+length in bytes supported by the authenticator as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxcredcntlst
+function returns the maximum supported number of credentials in
+a single credential ID list as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxcredidlen
+function returns the maximum supported length of a credential ID
+as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxrpid_minpinlen
+function returns the maximum number of RP IDs that may be passed to
+.Xr fido_dev_set_pin_minlen_rpid 3 ,
+as reported in
+.Fa ci .
+The minimum PIN length attribute is a CTAP 2.1 addition.
+If the attribute is not advertised by the authenticator, the
+.Fn fido_cbor_info_maxrpid_minpinlen
+function returns zero.
+.Pp
+The
+.Fn fido_cbor_info_maxlargeblob
+function returns the maximum length in bytes of an authenticator's
+serialized largeBlob array as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_minpinlen
+function returns the minimum PIN length enforced by the
+authenticator as reported in
+.Fa ci .
+The minimum PIN length attribute is a CTAP 2.1 addition.
+If the attribute is not advertised by the authenticator, the
+.Fn fido_cbor_info_minpinlen
+function returns zero.
+.Pp
+The
+.Fn fido_cbor_info_fwversion
+function returns the firmware version attribute of
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_uv_attempts
+function returns the number of UV attempts that the platform may
+attempt before falling back to PIN authentication.
+If 1, then all
+.Xr fido_dev_get_uv_retry_count 3
+retries are handled internally by the authenticator and the
+platform may only attempt non-PIN UV once.
+The UV attempts attribute is a CTAP 2.1 addition.
+If the attribute is not advertised by the authenticator,
+the
+.Fn fido_cbor_info_uv_attempts
+function returns zero.
+.Pp
+The
+.Fn fido_cbor_info_uv_modality
+function returns a bitmask representing different UV modes
+supported by the authenticator, as defined in the FIDO Registry of
+Predefined Values and reported in
+.Fa ci .
+See the
+.Em FIDO_UV_MODE_*
+definitions in
+.In fido/param.h
+for the set of values defined by libfido2 and a brief description
+of each.
+The UV modality attribute is a CTAP 2.1 addition.
+If the attribute is not advertised by the authenticator, the
+.Fn fido_cbor_info_uv_modality
+function returns zero.
+.Pp
+The
+.Fn fido_cbor_info_rk_remaining
+function returns the estimated number of additional
+resident/discoverable credentials that can be stored on the
+authenticator as reported in
+.Fa ci .
+The estimated number of remaining resident credentials is a
+CTAP 2.1 addition.
+If the attribute is not advertised by the authenticator, the
+.Fn fido_cbor_info_rk_remaining
+function returns -1.
+.Pp
+The
+.Fn fido_cbor_info_new_pin_required
+function returns whether a new PIN is required by the authenticator
+as reported in
+.Fa ci .
+If
+.Fn fido_cbor_info_new_pin_required
+returns true, operations requiring PIN authentication will fail
+until a new PIN is set on the authenticator.
+The
+.Xr fido_dev_set_pin 3
+function can be used to set a new PIN.
+.Pp
+A complete example of how to use these functions can be found in the
+.Pa example/info.c
+file shipped with
+.Em libfido2 .
+.Sh RETURN VALUES
+The
+.Fn fido_cbor_info_aaguid_ptr ,
+.Fn fido_cbor_info_extensions_ptr ,
+.Fn fido_cbor_info_protocols_ptr ,
+.Fn fido_cbor_info_transports_ptr ,
+.Fn fido_cbor_info_versions_ptr ,
+.Fn fido_cbor_info_options_name_ptr ,
+and
+.Fn fido_cbor_info_options_value_ptr
+functions return NULL if the respective field in
+.Fa ci
+is absent.
+If not NULL, returned pointers are guaranteed to exist until any
+API function that takes
+.Fa ci
+without the
+.Em const
+qualifier is invoked.
+.Sh SEE ALSO
+.Xr fido_dev_get_uv_retry_count 3 ,
+.Xr fido_dev_open 3 ,
+.Xr fido_dev_set_pin 3 ,
+.Xr fido_dev_set_pin_minlen_rpid 3
+.Rs
+.%D 2021-05-25
+.%O Review Draft, Version 2.2
+.%Q FIDO Alliance
+.%R FIDO Registry of Predefined Values
+.%U https://fidoalliance.org/specs/common-specs/fido-registry-v2.2-rd-20210525.html
+.Re
diff --git a/man/fido_cred_exclude.3 b/man/fido_cred_exclude.3
new file mode 100644
index 0000000..d5e840d
--- /dev/null
+++ b/man/fido_cred_exclude.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: December 2 2022 $
+.Dt FIDO_CRED_EXCLUDE 3
+.Os
+.Sh NAME
+.Nm fido_cred_exclude ,
+.Nm fido_cred_empty_exclude_list
+.Nd manage exclude lists in a FIDO2 credential
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_cred_exclude "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_empty_exclude_list "fido_cred_t *cred"
+.Sh DESCRIPTION
+The
+.Fn fido_cred_exclude
+function adds
+.Fa ptr
+to the list of credentials excluded by
+.Fa cred ,
+where
+.Fa ptr
+points to a credential ID of
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+If
+.Fn fido_cred_exclude
+fails, the existing list of excluded credentials is preserved.
+.Pp
+If
+.Nm
+returns success and
+.Fa cred
+is later passed to
+.Xr fido_dev_make_cred 3
+on a device that contains the credential
+denoted by
+.Fa ptr ,
+then
+.Xr fido_dev_make_cred 3
+will fail.
+.Pp
+For the format of a FIDO2 credential ID, please refer to the
+Web Authentication (webauthn) standard.
+.Pp
+The
+.Fn fido_cred_empty_exclude_list
+function empties the list of credentials excluded by
+.Fa cred .
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_cred_exclude
+and
+.Fn fido_cred_empty_exclude_list
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cred_new 3 ,
+.Xr fido_cred_set_authdata 3 ,
+.Xr fido_dev_make_cred 3
diff --git a/man/fido_cred_new.3 b/man/fido_cred_new.3
new file mode 100644
index 0000000..32ce768
--- /dev/null
+++ b/man/fido_cred_new.3
@@ -0,0 +1,356 @@
+.\" Copyright (c) 2018-2024 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 23 2018 $
+.Dt FIDO_CRED_NEW 3
+.Os
+.Sh NAME
+.Nm fido_cred_new ,
+.Nm fido_cred_free ,
+.Nm fido_cred_pin_minlen ,
+.Nm fido_cred_prot ,
+.Nm fido_cred_fmt ,
+.Nm fido_cred_rp_id ,
+.Nm fido_cred_rp_name ,
+.Nm fido_cred_user_name ,
+.Nm fido_cred_display_name ,
+.Nm fido_cred_authdata_ptr ,
+.Nm fido_cred_authdata_raw_ptr ,
+.Nm fido_cred_clientdata_hash_ptr ,
+.Nm fido_cred_id_ptr ,
+.Nm fido_cred_aaguid_ptr ,
+.Nm fido_cred_largeblob_key_ptr ,
+.Nm fido_cred_pubkey_ptr ,
+.Nm fido_cred_sig_ptr ,
+.Nm fido_cred_user_id_ptr ,
+.Nm fido_cred_x5c_list_count ,
+.Nm fido_cred_x5c_list_ptr ,
+.Nm fido_cred_x5c_ptr ,
+.Nm fido_cred_attstmt_ptr ,
+.Nm fido_cred_authdata_len ,
+.Nm fido_cred_authdata_raw_len ,
+.Nm fido_cred_clientdata_hash_len ,
+.Nm fido_cred_id_len ,
+.Nm fido_cred_aaguid_len ,
+.Nm fido_cred_largeblob_key_len ,
+.Nm fido_cred_pubkey_len ,
+.Nm fido_cred_sig_len ,
+.Nm fido_cred_user_id_len ,
+.Nm fido_cred_x5c_list_len ,
+.Nm fido_cred_x5c_len ,
+.Nm fido_cred_attstmt_len ,
+.Nm fido_cred_type ,
+.Nm fido_cred_flags ,
+.Nm fido_cred_sigcount
+.Nd FIDO2 credential API
+.Sh SYNOPSIS
+.In fido.h
+.Ft fido_cred_t *
+.Fn fido_cred_new "void"
+.Ft void
+.Fn fido_cred_free "fido_cred_t **cred_p"
+.Ft size_t
+.Fn fido_cred_pin_minlen "const fido_cred_t *cred"
+.Ft int
+.Fn fido_cred_prot "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_fmt "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_rp_id "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_rp_name "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_user_name "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_display_name "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_authdata_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_authdata_raw_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_clientdata_hash_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_id_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_aaguid_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_largeblob_key_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_pubkey_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_sig_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_user_id_ptr "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_x5c_list_count "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_x5c_list_ptr "const fido_cred_t *cred" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_cred_x5c_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
+.Fn fido_cred_attstmt_ptr "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_authdata_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_authdata_raw_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_clientdata_hash_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_id_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_aaguid_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_largeblob_key_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_pubkey_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_sig_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_user_id_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_x5c_list_len "const fido_cred_t *cred" "size_t idx"
+.Ft size_t
+.Fn fido_cred_x5c_len "const fido_cred_t *cred"
+.Ft size_t
+.Fn fido_cred_attstmt_len "const fido_cred_t *cred"
+.Ft int
+.Fn fido_cred_type "const fido_cred_t *cred"
+.Ft uint8_t
+.Fn fido_cred_flags "const fido_cred_t *cred"
+.Ft uint32_t
+.Fn fido_cred_sigcount "const fido_cred_t *cred"
+.Sh DESCRIPTION
+FIDO2 credentials are abstracted in
+.Em libfido2
+by the
+.Vt fido_cred_t
+type.
+The functions described in this page allow a
+.Vt fido_cred_t
+type to be allocated, deallocated, and inspected.
+For other operations on
+.Vt fido_cred_t ,
+please refer to
+.Xr fido_cred_set_authdata 3 ,
+.Xr fido_cred_exclude 3 ,
+.Xr fido_cred_verify 3 ,
+and
+.Xr fido_dev_make_cred 3 .
+.Pp
+The
+.Fn fido_cred_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_cred_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_cred_free
+function releases the memory backing
+.Fa *cred_p ,
+where
+.Fa *cred_p
+must have been previously allocated by
+.Fn fido_cred_new .
+On return,
+.Fa *cred_p
+is set to NULL.
+Either
+.Fa cred_p
+or
+.Fa *cred_p
+may be NULL, in which case
+.Fn fido_cred_free
+is a NOP.
+.Pp
+If the CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension is enabled on
+.Fa cred ,
+then the
+.Fn fido_cred_pin_minlen
+function returns the minimum PIN length of
+.Fa cred .
+Otherwise,
+.Fn fido_cred_pin_minlen
+returns zero.
+See
+.Xr fido_cred_set_pin_minlen 3
+on how to enable this extension.
+.Pp
+If the CTAP 2.1
+.Dv FIDO_EXT_CRED_PROTECT
+extension is enabled on
+.Fa cred ,
+then the
+.Fn fido_cred_prot
+function returns the protection of
+.Fa cred .
+Otherwise,
+.Fn fido_cred_prot
+returns zero.
+See
+.Xr fido_cred_set_prot 3
+for the protection policies understood by
+.Em libfido2 .
+.Pp
+The
+.Fn fido_cred_fmt
+function returns a pointer to a NUL-terminated string containing
+the attestation statement format identifier of
+.Fa cred ,
+or NULL if
+.Fa cred
+does not have a format set.
+.Pp
+The
+.Fn fido_cred_rp_id ,
+.Fn fido_cred_rp_name ,
+.Fn fido_cred_user_name ,
+and
+.Fn fido_cred_display_name
+functions return pointers to NUL-terminated strings holding the
+relying party ID, relying party name, user name, and user display
+name attributes of
+.Fa cred ,
+or NULL if the respective entry is not set.
+.Pp
+The
+.Fn fido_cred_authdata_ptr ,
+.Fn fido_cred_authdata_raw_ptr ,
+.Fn fido_cred_clientdata_hash_ptr ,
+.Fn fido_cred_id_ptr ,
+.Fn fido_cred_aaguid_ptr ,
+.Fn fido_cred_largeblob_key_ptr ,
+.Fn fido_cred_pubkey_ptr ,
+.Fn fido_cred_sig_ptr ,
+.Fn fido_cred_user_id_ptr ,
+.Fn fido_cred_x5c_ptr ,
+and
+.Fn fido_cred_attstmt_ptr
+functions return pointers to the CBOR-encoded and raw authenticator
+data, client data hash, ID, authenticator attestation GUID,
+.Dq largeBlobKey ,
+public key, signature, user ID, x509 leaf certificate, and attestation
+statement parts of
+.Fa cred ,
+or NULL if the respective entry is not set.
+.Pp
+The corresponding length can be obtained by
+.Fn fido_cred_authdata_len ,
+.Fn fido_cred_authdata_raw_len ,
+.Fn fido_cred_clientdata_hash_len ,
+.Fn fido_cred_id_len ,
+.Fn fido_cred_aaguid_len ,
+.Fn fido_cred_largeblob_key_len ,
+.Fn fido_cred_pubkey_len ,
+.Fn fido_cred_sig_len ,
+.Fn fido_cred_user_id_len ,
+.Fn fido_cred_x5c_len ,
+and
+.Fn fido_cred_attstmt_len .
+.Pp
+The
+.Fn fido_cred_x5c_list_count
+function returns the length of the x509 certificate chain in
+.Fa cred
+and the
+.Fn fido_cred_x5c_list_ptr
+and
+.Fn fido_cred_x5c_list_len
+functions return a pointer to and length of the x509 certificate at index
+.Fa idx
+respectively.
+Please note that the leaf certificate has an
+.Fa idx
+(index) value of 0 and calling
+.Fn fido_cred_x5c_list_ptr cred 0
+and
+.Fn fido_cred_x5c_list_len cred 0
+is equivalent to
+.Fn fido_cred_x5c_ptr cred
+and
+.Fn fido_cred_x5c_len cred
+respectively.
+If
+.Fa idx
+exceeds the return value of
+.Fn fido_cred_x5c_list_count ,
+.Fn fido_cred_x5c_list_ptr
+returns NULL and
+.Fn fido_cred_x5c_list_len
+returns 0.
+.Pp
+The authenticator data, x509 certificate, and signature parts of a
+credential are typically passed to a FIDO2 server for verification.
+.Pp
+The
+.Fn fido_cred_type
+function returns the COSE algorithm of
+.Fa cred .
+.Pp
+The
+.Fn fido_cred_flags
+function returns the authenticator data flags of
+.Fa cred .
+.Pp
+The
+.Fn fido_cred_sigcount
+function returns the authenticator data signature counter of
+.Fa cred .
+.Sh RETURN VALUES
+The authenticator data returned by
+.Fn fido_cred_authdata_ptr
+is a CBOR-encoded byte string, as obtained from the authenticator.
+To obtain the decoded byte string, use
+.Fn fido_cred_authdata_raw_ptr .
+.Pp
+If not NULL, pointers returned by
+.Fn fido_cred_fmt ,
+.Fn fido_cred_authdata_ptr ,
+.Fn fido_cred_clientdata_hash_ptr ,
+.Fn fido_cred_id_ptr ,
+.Fn fido_cred_aaguid_ptr ,
+.Fn fido_cred_largeblob_key_ptr ,
+.Fn fido_cred_pubkey_ptr ,
+.Fn fido_cred_sig_ptr ,
+and
+.Fn fido_cred_x5c_ptr
+are guaranteed to exist until any API function that takes
+.Fa cred
+without the
+.Em const
+qualifier is invoked.
+.Sh SEE ALSO
+.Xr fido_cred_exclude 3 ,
+.Xr fido_cred_set_authdata 3 ,
+.Xr fido_cred_set_pin_minlen 3 ,
+.Xr fido_cred_set_prot 3 ,
+.Xr fido_cred_verify 3 ,
+.Xr fido_credman_metadata_new 3 ,
+.Xr fido_dev_largeblob_get 3 ,
+.Xr fido_dev_make_cred 3
diff --git a/man/fido_cred_set_authdata.3 b/man/fido_cred_set_authdata.3
new file mode 100644
index 0000000..dd18802
--- /dev/null
+++ b/man/fido_cred_set_authdata.3
@@ -0,0 +1,402 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt FIDO_CRED_SET_AUTHDATA 3
+.Os
+.Sh NAME
+.Nm fido_cred_set_authdata ,
+.Nm fido_cred_set_authdata_raw ,
+.Nm fido_cred_set_attstmt ,
+.Nm fido_cred_set_attobj ,
+.Nm fido_cred_set_x509 ,
+.Nm fido_cred_set_sig ,
+.Nm fido_cred_set_id ,
+.Nm fido_cred_set_clientdata ,
+.Nm fido_cred_set_clientdata_hash ,
+.Nm fido_cred_set_rp ,
+.Nm fido_cred_set_user ,
+.Nm fido_cred_set_extensions ,
+.Nm fido_cred_set_blob ,
+.Nm fido_cred_set_pin_minlen ,
+.Nm fido_cred_set_prot ,
+.Nm fido_cred_set_rk ,
+.Nm fido_cred_set_uv ,
+.Nm fido_cred_set_fmt ,
+.Nm fido_cred_set_type
+.Nd set parameters of a FIDO2 credential
+.Sh SYNOPSIS
+.In fido.h
+.Bd -literal
+typedef enum {
+ FIDO_OPT_OMIT = 0, /* use authenticator's default */
+ FIDO_OPT_FALSE, /* explicitly set option to false */
+ FIDO_OPT_TRUE, /* explicitly set option to true */
+} fido_opt_t;
+.Ed
+.Ft int
+.Fn fido_cred_set_authdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_authdata_raw "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_attstmt "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_attobj "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_x509 "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_sig "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_id "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_clientdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_clientdata_hash "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_rp "fido_cred_t *cred" "const char *id" "const char *name"
+.Ft int
+.Fn fido_cred_set_user "fido_cred_t *cred" "const unsigned char *user_id" "size_t user_id_len" "const char *name" "const char *display_name" "const char *icon"
+.Ft int
+.Fn fido_cred_set_extensions "fido_cred_t *cred" "int flags"
+.Ft int
+.Fn fido_cred_set_blob "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
+.Ft int
+.Fn fido_cred_set_pin_minlen "fido_cred_t *cred" "size_t len"
+.Ft int
+.Fn fido_cred_set_prot "fido_cred_t *cred" "int prot"
+.Ft int
+.Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk"
+.Ft int
+.Fn fido_cred_set_uv "fido_cred_t *cred" "fido_opt_t uv"
+.Ft int
+.Fn fido_cred_set_fmt "fido_cred_t *cred" "const char *ptr"
+.Ft int
+.Fn fido_cred_set_type "fido_cred_t *cred" "int cose_alg"
+.Sh DESCRIPTION
+The
+.Nm
+set of functions define the various parameters of a FIDO2
+credential, allowing a
+.Fa fido_cred_t
+type to be prepared for a subsequent call to
+.Xr fido_dev_make_cred 3
+or
+.Xr fido_cred_verify 3 .
+For the complete specification of a FIDO2 credential and the format
+of its constituent parts, please refer to the Web Authentication
+(webauthn) standard.
+.Pp
+The
+.Fn fido_cred_set_authdata ,
+.Fn fido_cred_set_attstmt ,
+.Fn fido_cred_set_attobj ,
+.Fn fido_cred_set_x509 ,
+.Fn fido_cred_set_sig ,
+.Fn fido_cred_set_id ,
+and
+.Fn fido_cred_set_clientdata_hash
+functions set the authenticator data, attestation statement,
+attestation object, attestation certificate, attestation signature,
+id, and client data hash parts of
+.Fa cred
+to
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+.Pp
+The authenticator data passed to
+.Fn fido_cred_set_authdata
+must be a CBOR-encoded byte string, as obtained from
+.Fn fido_cred_authdata_ptr .
+Alternatively, a raw binary blob may be passed to
+.Fn fido_cred_set_authdata_raw .
+An application calling
+.Fn fido_cred_set_authdata
+does not need to call
+.Fn fido_cred_set_id .
+The latter is meant to be used in contexts where the
+credential's authenticator data is not available.
+.Pp
+The attestation statement passed to
+.Fn fido_cred_set_attstmt
+must be a CBOR-encoded map, as obtained from
+.Fn fido_cred_attstmt_ptr .
+An application calling
+.Fn fido_cred_set_attstmt
+does not need to call
+.Fn fido_cred_set_x509
+or
+.Fn fido_cred_set_sig .
+The latter two are meant to be used in contexts where the
+credential's complete attestation statement is not available or
+required.
+.Pp
+The attestation object passed to
+.Fn fido_cred_set_attobj
+must be a CBOR-encoded map containing
+.Dq authData ,
+.Dq fmt ,
+and
+.Dq attStmt .
+An application calling
+.Fn fido_cred_set_attobj
+does not need to call
+.Fn fido_cred_set_fmt ,
+.Fn fido_cred_set_attstmt ,
+.Fn fido_cred_set_authdata ,
+or
+.Fn fido_cred_set_authdata_raw .
+.Pp
+The
+.Fn fido_cred_set_clientdata
+function allows an application to set the client data hash of
+.Fa cred
+by specifying the credential's unhashed client data.
+This is required by Windows Hello, which calculates the client data
+hash internally.
+For compatibility with Windows Hello, applications should use
+.Fn fido_cred_set_clientdata
+instead of
+.Fn fido_cred_set_clientdata_hash .
+.Pp
+The
+.Fn fido_cred_set_rp
+function sets the relying party
+.Fa id
+and
+.Fa name
+parameters of
+.Fa cred ,
+where
+.Fa id
+and
+.Fa name
+are NUL-terminated UTF-8 strings.
+The contents of
+.Fa id
+and
+.Fa name
+are copied, and no references to the passed pointers are kept.
+.Pp
+The
+.Fn fido_cred_set_user
+function sets the user attributes of
+.Fa cred ,
+where
+.Fa user_id
+points to
+.Fa user_id_len
+bytes and
+.Fa name ,
+.Fa display_name ,
+and
+.Fa icon
+are NUL-terminated UTF-8 strings.
+The contents of
+.Fa user_id ,
+.Fa name ,
+.Fa display_name ,
+and
+.Fa icon
+are copied, and no references to the passed pointers are kept.
+Previously set user attributes are flushed.
+The
+.Fa user_id ,
+.Fa name ,
+.Fa display_name ,
+and
+.Fa icon
+parameters may be NULL.
+.Pp
+The
+.Fn fido_cred_set_extensions
+function sets the extensions of
+.Fa cred
+to the bitmask
+.Fa flags .
+At the moment, only the
+.Dv FIDO_EXT_CRED_BLOB ,
+.Dv FIDO_EXT_CRED_PROTECT ,
+.Dv FIDO_EXT_HMAC_SECRET ,
+.Dv FIDO_EXT_MINPINLEN ,
+and
+.Dv FIDO_EXT_LARGEBLOB_KEY
+extensions are supported.
+If
+.Fa flags
+is zero, the extensions of
+.Fa cred
+are cleared.
+.Pp
+The
+.Fn fido_cred_set_blob
+function sets the
+.Dq credBlob
+to be stored with
+.Fa cred
+to the data pointed to by
+.Fa ptr ,
+which must be
+.Fa len
+bytes long.
+.Pp
+The
+.Fn fido_cred_set_pin_minlen
+function enables the CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension on
+.Fa cred
+and sets the expected minimum PIN length of
+.Fa cred
+to
+.Fa len ,
+where
+.Fa len
+is greater than zero.
+If
+.Fa len
+is zero, the
+.Dv FIDO_EXT_MINPINLEN
+extension is disabled on
+.Fa cred .
+.Pp
+The
+.Fn fido_cred_set_prot
+function enables the CTAP 2.1
+.Dv FIDO_EXT_CRED_PROTECT
+extension on
+.Fa cred
+and sets the protection of
+.Fa cred
+to the scalar
+.Fa prot .
+At the moment, only the
+.Dv FIDO_CRED_PROT_UV_OPTIONAL ,
+.Dv FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID ,
+and
+.Dv FIDO_CRED_PROT_UV_REQUIRED
+protections are supported.
+If
+.Fa prot
+is zero, the protection of
+.Fa cred
+is cleared.
+.Pp
+The
+.Fn fido_cred_set_rk
+and
+.Fn fido_cred_set_uv
+functions set the
+.Em rk
+.Pq resident/discoverable key
+and
+.Em uv
+.Pq user verification
+attributes of
+.Fa cred .
+Both are
+.Dv FIDO_OPT_OMIT
+by default, allowing the authenticator to use its default settings.
+.Pp
+The
+.Fn fido_cred_set_fmt
+function sets the attestation statement format identifier of
+.Fa cred
+to
+.Fa fmt ,
+where
+.Fa fmt
+must be
+.Vt "packed"
+.Pq the format used in FIDO2 ,
+.Vt "fido-u2f"
+.Pq the format used in U2F ,
+.Vt "tpm"
+.Pq the format used by TPM-based authenticators ,
+or
+.Vt "none" .
+A copy of
+.Fa fmt
+is made, and no references to the passed pointer are kept.
+Note that not all authenticators support FIDO2 and therefore may only
+be able to generate
+.Vt fido-u2f
+attestation statements.
+.Pp
+The
+.Fn fido_cred_set_type
+function sets the type of
+.Fa cred to
+.Fa cose_alg ,
+where
+.Fa cose_alg
+is
+.Dv COSE_ES256 ,
+.Dv COSE_ES384 ,
+.Dv COSE_RS256 ,
+or
+.Dv COSE_EDDSA .
+The type of a credential may only be set once.
+Note that not all authenticators support COSE_RS256, COSE_ES384, or
+COSE_EDDSA.
+.Pp
+Use of the
+.Nm
+set of functions may happen in two distinct situations:
+when generating a new credential on a FIDO2 device, prior to
+.Xr fido_dev_make_cred 3
+(i.e, in the context of a FIDO2 client), or when validating
+a generated credential using
+.Xr fido_cred_verify 3
+(i.e, in the context of a FIDO2 server).
+.Pp
+For a complete description of the generation of a FIDO2 credential
+and its verification, please refer to the FIDO2 specification.
+A concrete utilisation example of the
+.Nm
+set of functions can be found in the
+.Pa cred.c
+example shipped with
+.Em libfido2 .
+.Sh RETURN VALUES
+The error codes returned by the
+.Nm
+set of functions are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cred_exclude 3 ,
+.Xr fido_cred_verify 3 ,
+.Xr fido_dev_make_cred 3
diff --git a/man/fido_cred_verify.3 b/man/fido_cred_verify.3
new file mode 100644
index 0000000..9548870
--- /dev/null
+++ b/man/fido_cred_verify.3
@@ -0,0 +1,114 @@
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 23 2018 $
+.Dt FIDO_CRED_VERIFY 3
+.Os
+.Sh NAME
+.Nm fido_cred_verify ,
+.Nm fido_cred_verify_self
+.Nd verify the attestation signature of a FIDO2 credential
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_cred_verify "const fido_cred_t *cred"
+.Ft int
+.Fn fido_cred_verify_self "const fido_cred_t *cred"
+.Sh DESCRIPTION
+The
+.Fn fido_cred_verify
+and
+.Fn fido_cred_verify_self
+functions verify whether the attestation signature contained in
+.Fa cred
+matches the attributes of the credential.
+Before using
+.Fn fido_cred_verify
+or
+.Fn fido_cred_verify_self
+in a sensitive context, the reader is strongly encouraged to make
+herself familiar with the FIDO2 credential attestation process
+as defined in the Web Authentication (webauthn) standard.
+.Pp
+The
+.Fn fido_cred_verify
+function verifies whether the client data hash, relying party ID,
+credential ID, type, protection policy, minimum PIN length, and
+resident/discoverable key and user verification attributes of
+.Fa cred
+have been attested by the holder of the private counterpart of
+the public key contained in the credential's x509 certificate.
+.Pp
+Please note that the x509 certificate itself is not verified.
+.Pp
+The attestation statement formats supported by
+.Fn fido_cred_verify
+are
+.Em packed ,
+.Em fido-u2f ,
+and
+.Em tpm .
+The attestation type implemented by
+.Fn fido_cred_verify
+is
+.Em Basic Attestation .
+.Pp
+The
+.Fn fido_cred_verify_self
+function verifies whether the client data hash, relying party ID,
+credential ID, type, protection policy, minimum PIN length, and
+resident/discoverable key and user verification attributes of
+.Fa cred
+have been attested by the holder of the credential's private key.
+.Pp
+The attestation statement formats supported by
+.Fn fido_cred_verify_self
+are
+.Em packed
+and
+.Em fido-u2f .
+The attestation type implemented by
+.Fn fido_cred_verify_self
+is
+.Em Self Attestation .
+.Pp
+Other attestation formats and types are not supported.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_cred_verify
+and
+.Fn fido_cred_verify_self
+are defined in
+.In fido/err.h .
+If
+.Fa cred
+passes verification, then
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cred_new 3 ,
+.Xr fido_cred_set_authdata 3
diff --git a/man/fido_credman_metadata_new.3 b/man/fido_credman_metadata_new.3
new file mode 100644
index 0000000..122020b
--- /dev/null
+++ b/man/fido_credman_metadata_new.3
@@ -0,0 +1,349 @@
+.\" Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: June 28 2019 $
+.Dt FIDO_CREDMAN_METADATA_NEW 3
+.Os
+.Sh NAME
+.Nm fido_credman_metadata_new ,
+.Nm fido_credman_rk_new ,
+.Nm fido_credman_rp_new ,
+.Nm fido_credman_metadata_free ,
+.Nm fido_credman_rk_free ,
+.Nm fido_credman_rp_free ,
+.Nm fido_credman_rk_existing ,
+.Nm fido_credman_rk_remaining ,
+.Nm fido_credman_rk ,
+.Nm fido_credman_rk_count ,
+.Nm fido_credman_rp_id ,
+.Nm fido_credman_rp_name ,
+.Nm fido_credman_rp_count ,
+.Nm fido_credman_rp_id_hash_ptr ,
+.Nm fido_credman_rp_id_hash_len ,
+.Nm fido_credman_get_dev_metadata ,
+.Nm fido_credman_get_dev_rk ,
+.Nm fido_credman_set_dev_rk ,
+.Nm fido_credman_del_dev_rk ,
+.Nm fido_credman_get_dev_rp
+.Nd FIDO2 credential management API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/credman.h
+.Ft fido_credman_metadata_t *
+.Fn fido_credman_metadata_new "void"
+.Ft fido_credman_rk_t *
+.Fn fido_credman_rk_new "void"
+.Ft fido_credman_rp_t *
+.Fn fido_credman_rp_new "void"
+.Ft void
+.Fn fido_credman_metadata_free "fido_credman_metadata_t **metadata_p"
+.Ft void
+.Fn fido_credman_rk_free "fido_credman_rk_t **rk_p"
+.Ft void
+.Fn fido_credman_rp_free "fido_credman_rp_t **rp_p"
+.Ft uint64_t
+.Fn fido_credman_rk_existing "const fido_credman_metadata_t *metadata"
+.Ft uint64_t
+.Fn fido_credman_rk_remaining "const fido_credman_metadata_t *metadata"
+.Ft const fido_cred_t *
+.Fn fido_credman_rk "const fido_credman_rk_t *rk" "size_t idx"
+.Ft size_t
+.Fn fido_credman_rk_count "const fido_credman_rk_t *rk"
+.Ft const char *
+.Fn fido_credman_rp_id "const fido_credman_rp_t *rp" "size_t idx"
+.Ft const char *
+.Fn fido_credman_rp_name "const fido_credman_rp_t *rp" "size_t idx"
+.Ft size_t
+.Fn fido_credman_rp_count "const fido_credman_rp_t *rp"
+.Ft const unsigned char *
+.Fn fido_credman_rp_id_hash_ptr "const fido_credman_rp_t *rp" "size_t idx"
+.Ft size_t
+.Fn fido_credman_rp_id_hash_len "const fido_credman_rp_t *" "size_t idx"
+.Ft int
+.Fn fido_credman_get_dev_metadata "fido_dev_t *dev" "fido_credman_metadata_t *metadata" "const char *pin"
+.Ft int
+.Fn fido_credman_get_dev_rk "fido_dev_t *dev" "const char *rp_id" "fido_credman_rk_t *rk" "const char *pin"
+.Ft int
+.Fn fido_credman_set_dev_rk "fido_dev_t *dev" "fido_cred_t *cred" "const char *pin"
+.Ft int
+.Fn fido_credman_del_dev_rk "fido_dev_t *dev" "const unsigned char *cred_id" "size_t cred_id_len" "const char *pin"
+.Ft int
+.Fn fido_credman_get_dev_rp "fido_dev_t *dev" "fido_credman_rp_t *rp" "const char *pin"
+.Sh DESCRIPTION
+The credential management API of
+.Em libfido2
+allows resident credentials on a FIDO2 authenticator to be listed,
+inspected, modified, and removed.
+Please note that not all FIDO2 authenticators support credential
+management.
+To obtain information on what an authenticator supports, please
+refer to
+.Xr fido_cbor_info_new 3 .
+.Pp
+The
+.Vt fido_credman_metadata_t
+type abstracts credential management metadata.
+.Pp
+The
+.Fn fido_credman_metadata_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_credman_metadata_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_credman_metadata_free
+function releases the memory backing
+.Fa *metadata_p ,
+where
+.Fa *metadata_p
+must have been previously allocated by
+.Fn fido_credman_metadata_new .
+On return,
+.Fa *metadata_p
+is set to NULL.
+Either
+.Fa metadata_p
+or
+.Fa *metadata_p
+may be NULL, in which case
+.Fn fido_credman_metadata_free
+is a NOP.
+.Pp
+The
+.Fn fido_credman_get_dev_metadata
+function populates
+.Fa metadata
+with information retrieved from
+.Fa dev .
+A valid
+.Fa pin
+must be provided.
+.Pp
+The
+.Fn fido_credman_rk_existing
+function inspects
+.Fa metadata
+and returns the number of resident credentials on the
+authenticator.
+The
+.Fn fido_credman_rk_remaining
+function inspects
+.Fa metadata
+and returns the estimated number of resident credentials that can
+be created on the authenticator.
+.Pp
+The
+.Vt fido_credman_rk_t
+type abstracts the set of resident credentials belonging to a
+given relying party.
+.Pp
+The
+.Fn fido_credman_rk_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_credman_rk_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_credman_rk_free
+function releases the memory backing
+.Fa *rk_p ,
+where
+.Fa *rk_p
+must have been previously allocated by
+.Fn fido_credman_rk_new .
+On return,
+.Fa *rk_p
+is set to NULL.
+Either
+.Fa rk_p
+or
+.Fa *rk_p
+may be NULL, in which case
+.Fn fido_credman_rk_free
+is a NOP.
+.Pp
+The
+.Fn fido_credman_get_dev_rk
+function populates
+.Fa rk
+with the set of resident credentials belonging to
+.Fa rp_id
+in
+.Fa dev .
+A valid
+.Fa pin
+must be provided.
+.Pp
+The
+.Fn fido_credman_rk_count
+function returns the number of resident credentials in
+.Fa rk .
+The
+.Fn fido_credman_rk
+function returns a pointer to the credential at index
+.Fa idx
+in
+.Fa rk .
+Please note that the first credential in
+.Fa rk
+has an
+.Fa idx
+(index) value of 0.
+.Pp
+The
+.Fn fido_credman_set_dev_rk
+function updates the credential pointed to by
+.Fa cred
+in
+.Fa dev .
+The credential id and user id attributes of
+.Fa cred
+must be set.
+See
+.Xr fido_cred_set_id 3
+and
+.Xr fido_cred_set_user 3
+for details.
+Only a credential's user attributes (name, display name)
+may be updated at this time.
+.Pp
+The
+.Fn fido_credman_del_dev_rk
+function deletes the resident credential identified by
+.Fa cred_id
+from
+.Fa dev ,
+where
+.Fa cred_id
+points to
+.Fa cred_id_len
+bytes.
+A valid
+.Fa pin
+must be provided.
+.Pp
+The
+.Vt fido_credman_rp_t
+type abstracts information about a relying party.
+.Pp
+The
+.Fn fido_credman_rp_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_credman_rp_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_credman_rp_free
+function releases the memory backing
+.Fa *rp_p ,
+where
+.Fa *rp_p
+must have been previously allocated by
+.Fn fido_credman_rp_new .
+On return,
+.Fa *rp_p
+is set to NULL.
+Either
+.Fa rp_p
+or
+.Fa *rp_p
+may be NULL, in which case
+.Fn fido_credman_rp_free
+is a NOP.
+.Pp
+The
+.Fn fido_credman_get_dev_rp
+function populates
+.Fa rp
+with information about relying parties with resident credentials
+in
+.Fa dev .
+A valid
+.Fa pin
+must be provided.
+.Pp
+The
+.Fn fido_credman_rp_count
+function returns the number of relying parties in
+.Fa rp .
+.Pp
+The
+.Fn fido_credman_rp_id
+and
+.Fn fido_credman_rp_name
+functions return pointers to the id and name of relying party
+.Fa idx
+in
+.Fa rp .
+If not NULL, the values returned by these functions point to
+NUL-terminated UTF-8 strings.
+Please note that the first relying party in
+.Fa rp
+has an
+.Fa idx
+(index) value of 0.
+.Pp
+The
+.Fn fido_credman_rp_id_hash_ptr
+function returns a pointer to the hashed id of relying party
+.Fa idx
+in
+.Fa rp .
+The corresponding length can be obtained by
+.Fn fido_credman_rp_id_hash_len .
+Please note that the first relying party in
+.Fa rp
+has an
+.Fa idx
+(index) value of 0.
+.Sh RETURN VALUES
+The
+.Fn fido_credman_get_dev_metadata ,
+.Fn fido_credman_get_dev_rk ,
+.Fn fido_credman_set_dev_rk ,
+.Fn fido_credman_del_dev_rk ,
+and
+.Fn fido_credman_get_dev_rp
+functions return
+.Dv FIDO_OK
+on success.
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+Functions returning pointers are not guaranteed to succeed, and
+should have their return values checked for NULL.
+.Sh SEE ALSO
+.Xr fido_cbor_info_new 3 ,
+.Xr fido_cred_new 3 ,
+.Xr fido_dev_supports_credman 3
+.Sh CAVEATS
+Resident credentials are called
+.Dq discoverable credentials
+in CTAP 2.1.
diff --git a/man/fido_dev_enable_entattest.3 b/man/fido_dev_enable_entattest.3
new file mode 100644
index 0000000..7617f22
--- /dev/null
+++ b/man/fido_dev_enable_entattest.3
@@ -0,0 +1,149 @@
+.\" Copyright (c) 2020-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: March 30 2022 $
+.Dt FIDO_DEV_ENABLE_ENTATTEST 3
+.Os
+.Sh NAME
+.Nm fido_dev_enable_entattest ,
+.Nm fido_dev_toggle_always_uv ,
+.Nm fido_dev_force_pin_change ,
+.Nm fido_dev_set_pin_minlen ,
+.Nm fido_dev_set_pin_minlen_rpid
+.Nd CTAP 2.1 configuration authenticator API
+.Sh SYNOPSIS
+.In fido.h
+.In fido/config.h
+.Ft int
+.Fn fido_dev_enable_entattest "fido_dev_t *dev" "const char *pin"
+.Ft int
+.Fn fido_dev_toggle_always_uv "fido_dev_t *dev" "const char *pin"
+.Ft int
+.Fn fido_dev_force_pin_change "fido_dev_t *dev" "const char *pin"
+.Ft int
+.Fn fido_dev_set_pin_minlen "fido_dev_t *dev" "size_t len" "const char *pin"
+.Ft int
+.Fn fido_dev_set_pin_minlen_rpid "fido_dev_t *dev" "const char * const *rpid" "size_t n" "const char *pin"
+.Sh DESCRIPTION
+The functions described in this page allow configuration of a
+CTAP 2.1 authenticator.
+.Pp
+The
+.Fn fido_dev_enable_entattest
+function enables the
+.Em Enterprise Attestation
+feature on
+.Fa dev .
+.Em Enterprise Attestation
+instructs the authenticator to include uniquely identifying
+information in subsequent attestation statements.
+The
+.Fa pin
+parameter may be NULL if
+.Fa dev
+does not have a PIN set.
+.Pp
+The
+.Fn fido_dev_toggle_always_uv
+function toggles the
+.Dq user verification always
+feature on
+.Fa dev .
+When set, this toggle enforces user verification at the
+authenticator level for all known credentials.
+If
+.Fa dev
+supports U2F (CTAP1) and the user verification methods supported by
+the authenticator do not allow protection of U2F credentials, the
+U2F subsystem will be disabled by the authenticator.
+The
+.Fa pin
+parameter may be NULL if
+.Fa dev
+does not have a PIN set.
+.Pp
+The
+.Fn fido_dev_force_pin_change
+function instructs
+.Fa dev
+to require a PIN change.
+Subsequent PIN authentication attempts against
+.Fa dev
+will fail until its PIN is changed.
+.Pp
+The
+.Fn fido_dev_set_pin_minlen
+function sets the minimum PIN length of
+.Fa dev
+to
+.Fa len .
+Minimum PIN lengths may only be increased.
+.Pp
+The
+.Fn fido_dev_set_pin_minlen_rpid
+function sets the list of relying party identifiers
+.Pq RP IDs
+that are allowed to obtain the minimum PIN length of
+.Fa dev
+through the CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension.
+The list of RP identifiers is denoted by
+.Fa rpid ,
+a vector of
+.Fa n
+NUL-terminated UTF-8 strings.
+A copy of
+.Fa rpid
+is made, and no reference to it or its contents is kept.
+The maximum value of
+.Fa n
+supported by the authenticator can be obtained using
+.Xr fido_cbor_info_maxrpid_minpinlen 3 .
+.Pp
+Configuration settings are reflected in the payload returned by the
+authenticator in response to a
+.Xr fido_dev_get_cbor_info 3
+call.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_enable_entattest ,
+.Fn fido_dev_toggle_always_uv ,
+.Fn fido_dev_force_pin_change ,
+.Fn fido_dev_set_pin_minlen ,
+and
+.Fn fido_dev_set_pin_minlen_rpid
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cbor_info_maxrpid_minpinlen 3 ,
+.Xr fido_cred_pin_minlen 3 ,
+.Xr fido_dev_get_cbor_info 3 ,
+.Xr fido_dev_reset 3
diff --git a/man/fido_dev_get_assert.3 b/man/fido_dev_get_assert.3
new file mode 100644
index 0000000..bb2fc43
--- /dev/null
+++ b/man/fido_dev_get_assert.3
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 24 2018 $
+.Dt FIDO_DEV_GET_ASSERT 3
+.Os
+.Sh NAME
+.Nm fido_dev_get_assert
+.Nd obtains an assertion from a FIDO2 device
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_get_assert "fido_dev_t *dev" "fido_assert_t *assert" "const char *pin"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_get_assert
+function asks the FIDO2 device represented by
+.Fa dev
+for an assertion according to the following parameters defined in
+.Fa assert :
+.Pp
+.Bl -dash -compact
+.It
+.Nm relying party ID ;
+.It
+.Nm client data hash ;
+.It
+.Nm list of allowed credential IDs ;
+.It
+.Nm user presence and user verification attributes .
+.El
+.Pp
+See
+.Xr fido_assert_set_authdata 3
+for information on how these values are set.
+.Pp
+If a PIN is not needed to authenticate the request against
+.Fa dev ,
+then
+.Fa pin
+may be NULL.
+Otherwise
+.Fa pin
+must point to a NUL-terminated UTF-8 string.
+.Pp
+After a successful call to
+.Fn fido_dev_get_assert ,
+the
+.Xr fido_assert_count 3 ,
+.Xr fido_assert_user_display_name 3 ,
+.Xr fido_assert_user_icon 3 ,
+.Xr fido_assert_user_name 3 ,
+.Xr fido_assert_authdata_ptr 3 ,
+.Xr fido_assert_user_id_ptr 3 ,
+.Xr fido_assert_sig_ptr 3 ,
+and
+.Xr fido_assert_sigcount 3
+functions may be invoked on
+.Fa assert
+to retrieve the various attributes of the generated assertion.
+.Pp
+Please note that
+.Fn fido_dev_get_assert
+is synchronous and will block if necessary.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_get_assert
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_assert_new 3 ,
+.Xr fido_assert_set_authdata 3
diff --git a/man/fido_dev_get_touch_begin.3 b/man/fido_dev_get_touch_begin.3
new file mode 100644
index 0000000..f015eff
--- /dev/null
+++ b/man/fido_dev_get_touch_begin.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2020 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: August 5 2020 $
+.Dt FIDO_DEV_GET_TOUCH_BEGIN 3
+.Os
+.Sh NAME
+.Nm fido_dev_get_touch_begin ,
+.Nm fido_dev_get_touch_status
+.Nd asynchronously wait for touch on a FIDO2 authenticator
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_get_touch_begin "fido_dev_t *dev"
+.Ft int
+.Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int ms"
+.Sh DESCRIPTION
+The functions described in this page allow an application to
+asynchronously wait for touch on a FIDO2 authenticator.
+This is useful when multiple authenticators are present and
+the application needs to know which one to use.
+.Pp
+The
+.Fn fido_dev_get_touch_begin
+function initiates a touch request on
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_get_touch_status
+function continues an ongoing touch request on
+.Fa dev ,
+blocking up to
+.Fa ms
+milliseconds.
+On success,
+.Fa touched
+will be updated to reflect the touch request status.
+If
+.Fa touched
+is 1, the device was touched, and the touch request is
+terminated.
+If
+.Fa touched
+is 0, the application may call
+.Fn fido_dev_get_touch_status
+to continue the touch request, or
+.Fn fido_dev_cancel
+to terminate it.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_get_touch_begin
+and
+.Fn fido_dev_get_touch_status
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh EXAMPLES
+Please refer to
+.Em examples/select.c
+in
+.Em libfido2's
+source tree.
+.Sh SEE ALSO
+.Xr fido_dev_cancel 3
+.Sh CAVEATS
+The
+.Fn fido_dev_get_touch_status
+function will cause a command to be transmitted to U2F
+authenticators.
+These transmissions should not exceed a frequency of 5Hz.
diff --git a/man/fido_dev_info_manifest.3 b/man/fido_dev_info_manifest.3
new file mode 100644
index 0000000..a70a3cb
--- /dev/null
+++ b/man/fido_dev_info_manifest.3
@@ -0,0 +1,211 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: March 30 2022 $
+.Dt FIDO_DEV_INFO_MANIFEST 3
+.Os
+.Sh NAME
+.Nm fido_dev_info_manifest ,
+.Nm fido_dev_info_new ,
+.Nm fido_dev_info_free ,
+.Nm fido_dev_info_ptr ,
+.Nm fido_dev_info_path ,
+.Nm fido_dev_info_product ,
+.Nm fido_dev_info_vendor ,
+.Nm fido_dev_info_manufacturer_string ,
+.Nm fido_dev_info_product_string ,
+.Nm fido_dev_info_set
+.Nd FIDO2 device discovery functions
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_info_manifest "fido_dev_info_t *devlist" "size_t ilen" "size_t *olen"
+.Ft fido_dev_info_t *
+.Fn fido_dev_info_new "size_t n"
+.Ft void
+.Fn fido_dev_info_free "fido_dev_info_t **devlist_p" "size_t n"
+.Ft const fido_dev_info_t *
+.Fn fido_dev_info_ptr "const fido_dev_info_t *devlist" "size_t i"
+.Ft const char *
+.Fn fido_dev_info_path "const fido_dev_info_t *di"
+.Ft int16_t
+.Fn fido_dev_info_product "const fido_dev_info_t *di"
+.Ft int16_t
+.Fn fido_dev_info_vendor "const fido_dev_info_t *di"
+.Ft const char *
+.Fn fido_dev_info_manufacturer_string "const fido_dev_info_t *di"
+.Ft const char *
+.Fn fido_dev_info_product_string "const fido_dev_info_t *di"
+.Ft int
+.Fn fido_dev_info_set "fido_dev_info_t *devlist" "size_t i" "const char *path" "const char *manufacturer" "const char *product" "const fido_dev_io_t *io" "const fido_dev_transport_t *transport"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_info_manifest
+function fills
+.Fa devlist
+with up to
+.Fa ilen
+FIDO2 devices found by the underlying operating system.
+Currently only USB HID devices are supported.
+The number of discovered devices is returned in
+.Fa olen ,
+where
+.Fa olen
+is an addressable pointer.
+.Pp
+The
+.Fn fido_dev_info_new
+function returns a pointer to a newly allocated, empty device list
+with
+.Fa n
+available slots.
+If memory is not available, NULL is returned.
+.Pp
+The
+.Fn fido_dev_info_free
+function releases the memory backing
+.Fa *devlist_p ,
+where
+.Fa *devlist_p
+must have been previously allocated by
+.Fn fido_dev_info_new .
+The number
+.Fa n
+of allocated slots must also be provided.
+On return,
+.Fa *devlist_p
+is set to NULL.
+Either
+.Fa devlist_p
+or
+.Fa *devlist_p
+may be NULL, in which case
+.Fn fido_dev_info_free
+is a NOP.
+.Pp
+The
+.Fn fido_dev_info_ptr
+function returns a pointer to slot number
+.Fa i
+of
+.Fa devlist .
+It is the caller's responsibility to ensure that
+.Fa i
+is bounded.
+Please note that the first slot has index 0.
+.Pp
+The
+.Fn fido_dev_info_path
+function returns the filesystem path or subsystem-specific identification
+string of
+.Fa di .
+.Pp
+The
+.Fn fido_dev_info_product
+function returns the product ID of
+.Fa di .
+.Pp
+The
+.Fn fido_dev_info_vendor
+function returns the vendor ID of
+.Fa di .
+.Pp
+The
+.Fn fido_dev_info_manufacturer_string
+function returns the manufacturer string of
+.Fa di .
+If
+.Fa di
+does not have an associated manufacturer string,
+.Fn fido_dev_info_manufacturer_string
+returns an empty string.
+.Pp
+The
+.Fn fido_dev_info_product_string
+function returns the product string of
+.Fa di .
+If
+.Fa di
+does not have an associated product string,
+.Fn fido_dev_info_product_string
+returns an empty string.
+.Pp
+An example of how to use the functions described in this document
+can be found in the
+.Pa examples/manifest.c
+file shipped with
+.Em libfido2 .
+.Pp
+The
+.Fn fido_dev_info_set
+function initializes an entry in a device list allocated by
+.Fn fido_dev_info_new
+with the specified path, manufacturer, and product strings, and with
+the specified I/O handlers and, optionally, transport functions, as
+described in
+.Xr fido_dev_set_io_functions 3 .
+The
+.Fa io
+argument must be specified; the
+.Fa transport
+argument may be
+.Dv NULL .
+The path, I/O handlers, and transport functions will be used
+automatically by
+.Xr fido_dev_new_with_info 3
+and
+.Xr fido_dev_open_with_info 3 .
+An application can use this, for example, to substitute mock FIDO2
+devices in testing for the real ones that
+.Fn fido_dev_info_manifest
+would discover.
+.Sh RETURN VALUES
+The
+.Fn fido_dev_info_manifest
+function always returns
+.Dv FIDO_OK .
+If a discovery error occurs, the
+.Fa olen
+pointer is set to 0.
+.Pp
+On success, the
+.Fn fido_dev_info_set
+function returns
+.Dv FIDO_OK .
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Pp
+The pointers returned by
+.Fn fido_dev_info_ptr ,
+.Fn fido_dev_info_path ,
+.Fn fido_dev_info_manufacturer_string ,
+and
+.Fn fido_dev_info_product_string
+are guaranteed to exist until
+.Fn fido_dev_info_free
+is called on the corresponding device list.
diff --git a/man/fido_dev_largeblob_get.3 b/man/fido_dev_largeblob_get.3
new file mode 100644
index 0000000..12dd319
--- /dev/null
+++ b/man/fido_dev_largeblob_get.3
@@ -0,0 +1,216 @@
+.\" Copyright (c) 2020 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: October 26 2020 $
+.Dt FIDO_LARGEBLOB_GET 3
+.Os
+.Sh NAME
+.Nm fido_dev_largeblob_get ,
+.Nm fido_dev_largeblob_set ,
+.Nm fido_dev_largeblob_remove ,
+.Nm fido_dev_largeblob_get_array ,
+.Nm fido_dev_largeblob_set_array
+.Nd FIDO2 large blob API
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_largeblob_get "fido_dev_t *dev" "const unsigned char *key_ptr" "size_t key_len" "unsigned char **blob_ptr" "size_t *blob_len"
+.Ft int
+.Fn fido_dev_largeblob_set "fido_dev_t *dev" "const unsigned char *key_ptr" "size_t key_len" "const unsigned char *blob_ptr" "size_t blob_len" "const char *pin"
+.Ft int
+.Fn fido_dev_largeblob_remove "fido_dev_t *dev" "const unsigned char *key_ptr" "size_t key_len" "const char *pin"
+.Ft int
+.Fn fido_dev_largeblob_get_array "fido_dev_t *dev" "unsigned char **cbor_ptr" "size_t *cbor_len"
+.Ft int
+.Fn fido_dev_largeblob_set_array "fido_dev_t *dev" "const unsigned char *cbor_ptr" "size_t cbor_len" "const char *pin"
+.Sh DESCRIPTION
+The
+.Dq largeBlobs
+API of
+.Em libfido2
+allows binary blobs residing on a CTAP 2.1 authenticator to be
+read, written, and inspected.
+.Dq largeBlobs
+is a CTAP 2.1 extension.
+.Pp
+.Dq largeBlobs
+are stored as elements of a CBOR array.
+Confidentiality is ensured by encrypting each element with a
+distinct, credential-bound 256-bit AES-GCM key.
+The array is otherwise shared between different credentials and
+FIDO2 relying parties.
+.Pp
+Retrieval of a credential's encryption key is possible during
+enrollment with
+.Xr fido_cred_set_extensions 3
+and
+.Xr fido_cred_largeblob_key_ptr 3 ,
+during assertion with
+.Xr fido_assert_set_extensions 3
+and
+.Xr fido_assert_largeblob_key_ptr 3 ,
+or, in the case of a resident credential, via
+.Em libfido2's
+credential management API.
+.Pp
+The
+.Dq largeBlobs
+CBOR array is opaque to the authenticator.
+Management of the array is left at the discretion of FIDO2 clients.
+For further details on CTAP 2.1's
+.Dq largeBlobs
+extension, please refer to the CTAP 2.1 spec.
+.Pp
+The
+.Fn fido_dev_largeblob_get
+function retrieves the authenticator's
+.Dq largeBlobs
+CBOR array and, on success, returns the first blob
+.Pq iterating from array index zero
+that can be decrypted by
+.Fa key_ptr ,
+where
+.Fa key_ptr
+points to
+.Fa key_len
+bytes.
+On success,
+.Fn fido_dev_largeblob_get
+sets
+.Fa blob_ptr
+to the body of the decrypted blob, and
+.Fa blob_len
+to the length of the decrypted blob in bytes.
+It is the caller's responsibility to free
+.Fa blob_ptr .
+.Pp
+The
+.Fn fido_dev_largeblob_set
+function uses
+.Fa key_ptr
+to encrypt
+.Fa blob_ptr
+and inserts the result in the authenticator's
+.Dq largeBlobs
+CBOR array.
+Insertion happens at the end of the array if no existing element
+can be decrypted by
+.Fa key_ptr ,
+or at the position of the first element
+.Pq iterating from array index zero
+that can be decrypted by
+.Fa key_ptr .
+.Fa key_len
+holds the length of
+.Fa key_ptr
+in bytes, and
+.Fa blob_len
+the length of
+.Fa blob_ptr
+in bytes.
+A
+.Fa pin
+or equivalent user-verification gesture is required.
+.Pp
+The
+.Fn fido_dev_largeblob_remove
+function retrieves the authenticator's
+.Dq largeBlobs
+CBOR array and, on success, drops the first blob
+.Pq iterating from array index zero
+that can be decrypted by
+.Fa key_ptr ,
+where
+.Fa key_ptr
+points to
+.Fa key_len
+bytes.
+A
+.Fa pin
+or equivalent user-verification gesture is required.
+.Pp
+The
+.Fn fido_dev_largeblob_get_array
+function retrieves the authenticator's
+.Dq largeBlobs
+CBOR array and, on success,
+sets
+.Fa cbor_ptr
+to the body of the CBOR array, and
+.Fa cbor_len
+to its corresponding length in bytes.
+It is the caller's responsibility to free
+.Fa cbor_ptr .
+.Pp
+Finally, the
+.Fn fido_dev_largeblob_set_array
+function sets the authenticator's
+.Dq largeBlobs
+CBOR array to the data pointed to by
+.Fa cbor_ptr ,
+where
+.Fa cbor_ptr
+points to
+.Fa cbor_len
+bytes.
+A
+.Fa pin
+or equivalent user-verification gesture is required.
+.Sh RETURN VALUES
+The functions
+.Fn fido_dev_largeblob_set ,
+.Fn fido_dev_largeblob_get ,
+.Fn fido_dev_largeblob_remove ,
+.Fn fido_dev_largeblob_get_array ,
+and
+.Fn fido_dev_largeblob_set_array
+return
+.Dv FIDO_OK
+on success.
+On error, an error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr fido_assert_largeblob_key_len 3 ,
+.Xr fido_assert_largeblob_key_ptr 3 ,
+.Xr fido_assert_set_extensions 3 ,
+.Xr fido_cred_largeblob_key_len 3 ,
+.Xr fido_cred_largeblob_key_ptr 3 ,
+.Xr fido_cred_set_extensions 3 ,
+.Xr fido_credman_get_dev_rk 3 ,
+.Xr fido_credman_get_dev_rp 3 ,
+.Xr fido_dev_get_assert 3 ,
+.Xr fido_dev_make_cred 3
+.Sh CAVEATS
+The
+.Dq largeBlobs
+extension is not meant to be used to store sensitive data.
+When retrieved, a credential's
+.Dq largeBlobs
+encryption key is transmitted in the clear, and an authenticator's
+.Dq largeBlobs
+CBOR array can be read without user interaction or verification.
diff --git a/man/fido_dev_make_cred.3 b/man/fido_dev_make_cred.3
new file mode 100644
index 0000000..b13f9a1
--- /dev/null
+++ b/man/fido_dev_make_cred.3
@@ -0,0 +1,100 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 23 2018 $
+.Dt FIDO_DEV_MAKE_CRED 3
+.Os
+.Sh NAME
+.Nm fido_dev_make_cred
+.Nd generates a new credential on a FIDO2 device
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_make_cred "fido_dev_t *dev" "fido_cred_t *cred" "const char *pin"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_make_cred
+function asks the FIDO2 device represented by
+.Fa dev
+to generate a new credential according to the following parameters
+defined in
+.Fa cred :
+.Pp
+.Bl -dash -compact
+.It
+.Nm type ;
+.It
+.Nm client data hash ;
+.It
+.Nm relying party ;
+.It
+.Nm user attributes ;
+.It
+.Nm list of excluded credential IDs ;
+.It
+.Nm resident/discoverable key and user verification attributes .
+.El
+.Pp
+See
+.Xr fido_cred_set_authdata 3
+for information on how these values are set.
+.Pp
+If a PIN is not needed to authenticate the request against
+.Fa dev ,
+then
+.Fa pin
+may be NULL.
+Otherwise
+.Fa pin
+must point to a NUL-terminated UTF-8 string.
+.Pp
+After a successful call to
+.Fn fido_dev_make_cred ,
+the
+.Xr fido_cred_authdata_ptr 3 ,
+.Xr fido_cred_pubkey_ptr 3 ,
+.Xr fido_cred_x5c_ptr 3 ,
+and
+.Xr fido_cred_sig_ptr 3
+functions may be invoked on
+.Fa cred
+to retrieve the various parts of the generated credential.
+.Pp
+Please note that
+.Fn fido_dev_make_cred
+is synchronous and will block if necessary.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_make_cred
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cred_new 3 ,
+.Xr fido_cred_set_authdata 3
diff --git a/man/fido_dev_open.3 b/man/fido_dev_open.3
new file mode 100644
index 0000000..f839e26
--- /dev/null
+++ b/man/fido_dev_open.3
@@ -0,0 +1,316 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 25 2018 $
+.Dt FIDO_DEV_OPEN 3
+.Os
+.Sh NAME
+.Nm fido_dev_open ,
+.Nm fido_dev_open_with_info ,
+.Nm fido_dev_close ,
+.Nm fido_dev_cancel ,
+.Nm fido_dev_new ,
+.Nm fido_dev_new_with_info ,
+.Nm fido_dev_free ,
+.Nm fido_dev_force_fido2 ,
+.Nm fido_dev_force_u2f ,
+.Nm fido_dev_is_fido2 ,
+.Nm fido_dev_is_winhello ,
+.Nm fido_dev_supports_credman ,
+.Nm fido_dev_supports_cred_prot ,
+.Nm fido_dev_supports_permissions ,
+.Nm fido_dev_supports_pin ,
+.Nm fido_dev_supports_uv ,
+.Nm fido_dev_has_pin ,
+.Nm fido_dev_has_uv ,
+.Nm fido_dev_protocol ,
+.Nm fido_dev_build ,
+.Nm fido_dev_flags ,
+.Nm fido_dev_major ,
+.Nm fido_dev_minor
+.Nd FIDO2 device open/close and related functions
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_open "fido_dev_t *dev" "const char *path"
+.Ft int
+.Fn fido_dev_open_with_info "fido_dev_t *dev"
+.Ft int
+.Fn fido_dev_close "fido_dev_t *dev"
+.Ft int
+.Fn fido_dev_cancel "fido_dev_t *dev"
+.Ft fido_dev_t *
+.Fn fido_dev_new "void"
+.Ft fido_dev_t *
+.Fn fido_dev_new_with_info "const fido_dev_info_t *"
+.Ft void
+.Fn fido_dev_free "fido_dev_t **dev_p"
+.Ft void
+.Fn fido_dev_force_fido2 "fido_dev_t *dev"
+.Ft void
+.Fn fido_dev_force_u2f "fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_is_fido2 "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_is_winhello "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_credman "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_cred_prot "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_permissions "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_pin "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_uv "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_has_pin "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_has_uv "const fido_dev_t *dev"
+.Ft uint8_t
+.Fn fido_dev_protocol "const fido_dev_t *dev"
+.Ft uint8_t
+.Fn fido_dev_build "const fido_dev_t *dev"
+.Ft uint8_t
+.Fn fido_dev_flags "const fido_dev_t *dev"
+.Ft uint8_t
+.Fn fido_dev_major "const fido_dev_t *dev"
+.Ft uint8_t
+.Fn fido_dev_minor "const fido_dev_t *dev"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_open
+function opens the device pointed to by
+.Fa path ,
+where
+.Fa dev
+is a freshly allocated or otherwise closed
+.Vt fido_dev_t .
+If
+.Fa dev
+claims to be FIDO2,
+.Em libfido2
+will attempt to speak FIDO2 to
+.Fa dev .
+If that fails,
+.Em libfido2
+will fallback to U2F unless the
+.Dv FIDO_DISABLE_U2F_FALLBACK
+flag was set in
+.Xr fido_init 3 .
+.Pp
+The
+.Fn fido_dev_open_with_info
+function opens
+.Fa dev
+as previously allocated using
+.Fn fido_dev_new_with_info .
+.Pp
+The
+.Fn fido_dev_close
+function closes the device represented by
+.Fa dev .
+If
+.Fa dev
+is already closed,
+.Fn fido_dev_close
+is a NOP.
+.Pp
+The
+.Fn fido_dev_cancel
+function cancels any pending requests on
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_new
+function returns a pointer to a newly allocated, empty
+.Vt fido_dev_t .
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_dev_new_with_info
+function returns a pointer to a newly allocated
+.Vt fido_dev_t
+with
+.Vt fido_dev_info_t
+parameters, for use with
+.Xr fido_dev_info_manifest 3
+and
+.Fn fido_dev_open_with_info .
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn fido_dev_free
+function releases the memory backing
+.Fa *dev_p ,
+where
+.Fa *dev_p
+must have been previously allocated by
+.Fn fido_dev_new .
+On return,
+.Fa *dev_p
+is set to NULL.
+Either
+.Fa dev_p
+or
+.Fa *dev_p
+may be NULL, in which case
+.Fn fido_dev_free
+is a NOP.
+.Pp
+The
+.Fn fido_dev_force_fido2
+function can be used to force CTAP2 communication with
+.Fa dev ,
+where
+.Fa dev
+is an open device.
+.Pp
+The
+.Fn fido_dev_force_u2f
+function can be used to force CTAP1 (U2F) communication with
+.Fa dev ,
+where
+.Fa dev
+is an open device.
+.Pp
+The
+.Fn fido_dev_is_fido2
+function returns
+.Dv true
+if
+.Fa dev
+is a FIDO2 device.
+.Pp
+The
+.Fn fido_dev_is_winhello
+function returns
+.Dv true
+if
+.Fa dev
+is a Windows Hello device.
+.Pp
+The
+.Fn fido_dev_supports_credman
+function returns
+.Dv true
+if
+.Fa dev
+supports CTAP 2.1 Credential Management.
+.Pp
+The
+.Fn fido_dev_supports_cred_prot
+function returns
+.Dv true
+if
+.Fa dev
+supports CTAP 2.1 Credential Protection.
+.Pp
+The
+.Fn fido_dev_supports_permissions
+function returns
+.Dv true
+if
+.Fa dev
+supports CTAP 2.1 UV token permissions.
+.Pp
+The
+.Fn fido_dev_supports_pin
+function returns
+.Dv true
+if
+.Fa dev
+supports CTAP 2.0 Client PINs.
+.Pp
+The
+.Fn fido_dev_supports_uv
+function returns
+.Dv true
+if
+.Fa dev
+supports a built-in user verification method.
+.Pp
+The
+.Fn fido_dev_has_pin
+function returns
+.Dv true
+if
+.Fa dev
+has a CTAP 2.0 Client PIN set.
+.Pp
+The
+.Fn fido_dev_has_uv
+function returns
+.Dv true
+if
+.Fa dev
+supports built-in user verification and its user verification
+feature is configured.
+.Pp
+The
+.Fn fido_dev_protocol
+function returns the CTAPHID protocol version identifier of
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_build
+function returns the CTAPHID build version number of
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_flags
+function returns the CTAPHID capabilities flags of
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_major
+function returns the CTAPHID major version number of
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_minor
+function returns the CTAPHID minor version number of
+.Fa dev .
+.Pp
+For the format and meaning of the CTAPHID parameters returned by
+functions above, please refer to the FIDO Client to Authenticator
+Protocol (CTAP) specification.
+.Sh RETURN VALUES
+On success,
+.Fn fido_dev_open ,
+.Fn fido_dev_open_with_info ,
+and
+.Fn fido_dev_close
+return
+.Dv FIDO_OK .
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr fido_dev_info_manifest 3 ,
+.Xr fido_dev_set_io_functions 3 ,
+.Xr fido_init 3
diff --git a/man/fido_dev_set_io_functions.3 b/man/fido_dev_set_io_functions.3
new file mode 100644
index 0000000..e3e10ba
--- /dev/null
+++ b/man/fido_dev_set_io_functions.3
@@ -0,0 +1,261 @@
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 25 2018 $
+.Dt FIDO_DEV_SET_IO_FUNCTIONS 3
+.Os
+.Sh NAME
+.Nm fido_dev_set_io_functions ,
+.Nm fido_dev_set_sigmask ,
+.Nm fido_dev_set_timeout ,
+.Nm fido_dev_set_transport_functions ,
+.Nm fido_dev_io_handle
+.Nd FIDO2 device I/O interface
+.Sh SYNOPSIS
+.In fido.h
+.Bd -literal
+typedef void *fido_dev_io_open_t(const char *);
+typedef void fido_dev_io_close_t(void *);
+typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int);
+typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t);
+
+typedef struct fido_dev_io {
+ fido_dev_io_open_t *open;
+ fido_dev_io_close_t *close;
+ fido_dev_io_read_t *read;
+ fido_dev_io_write_t *write;
+} fido_dev_io_t;
+
+#ifdef _WIN32
+typedef int fido_sigset_t;
+#else
+typedef sigset_t fido_sigset_t;
+#endif
+
+typedef int fido_dev_rx_t(struct fido_dev *,
+ uint8_t, unsigned char *, size_t, int);
+typedef int fido_dev_tx_t(struct fido_dev *,
+ uint8_t, const unsigned char *, size_t);
+
+typedef struct fido_dev_transport {
+ fido_dev_rx_t *rx;
+ fido_dev_tx_t *tx;
+} fido_dev_transport_t;
+.Ed
+.Pp
+.Ft int
+.Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io"
+.Ft int
+.Fn fido_dev_set_sigmask "fido_dev_t *dev" "const fido_sigset_t *sigmask"
+.Ft int
+.Fn fido_dev_set_timeout "fido_dev_t *dev" "int ms"
+.Ft int
+.Fn fido_dev_set_transport_functions "fido_dev_t *dev" "const fido_dev_transport_t *t"
+.Ft void *
+.Fn fido_dev_io_handle "const fido_dev_t *dev"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_set_io_functions
+function sets the I/O handlers used by
+.Em libfido2
+to talk to
+.Fa dev .
+By default, these handlers are set to the operating system's native HID or NFC
+interfaces.
+They are defined as follows:
+.Bl -tag -width Ds
+.It Vt fido_dev_open_t
+Receives a
+.Vt const char *
+holding a path and opens the corresponding device, returning a
+non-NULL opaque pointer on success and NULL on error.
+.It Vt fido_dev_close_t
+Receives the opaque pointer returned by
+.Vt fido_dev_open_t
+and closes the device.
+.It Vt fido_dev_read_t
+Reads a single transmission unit (HID report, APDU) from a device.
+The first parameter is the opaque pointer returned by
+.Vt fido_dev_open_t .
+The second parameter is the read buffer, and the third parameter
+is the read buffer size.
+The fourth parameter is the number of milliseconds the caller is
+willing to sleep, should the call need to block.
+If this value holds -1,
+.Vt fido_dev_read_t
+may block indefinitely.
+On success, the number of bytes read is returned.
+On error, -1 is returned.
+.It Vt fido_dev_write_t
+Writes a single transmission unit (HID report, APDU) to
+.Fa dev .
+The first parameter is the opaque pointer returned by
+.Vt fido_dev_open_t .
+The second parameter is the write buffer, and the third parameter
+is the number of bytes to be written.
+A
+.Vt fido_dev_write_t
+may block.
+On success, the number of bytes written is returned.
+On error, -1 is returned.
+.El
+.Pp
+When calling
+.Fn fido_dev_set_io_functions ,
+the
+.Fa open ,
+.Fa close ,
+.Fa read ,
+and
+.Fa write
+fields of
+.Fa io
+may not be NULL.
+.Pp
+No references to
+.Fa io
+are held by
+.Fn fido_dev_set_io_functions .
+.Pp
+The
+.Fn fido_dev_set_sigmask
+function may be used to specify a non-NULL signal mask
+.Fa sigmask
+to be used while
+.Em libfido2's
+default I/O handlers wait on
+.Fa dev .
+On UNIX-like operating systems,
+.Vt fido_sigset_t
+is defined as
+.Vt sigset_t .
+On Windows,
+.Vt fido_sigset_t
+is defined as
+.Vt int
+and
+.Fn fido_dev_set_sigmask
+is a no-op.
+.Pp
+No references to
+.Fa sigmask
+are held by
+.Fn fido_dev_set_sigmask .
+.Pp
+The
+.Fn fido_dev_set_timeout
+function informs
+.Em libfido2
+not to block for more than
+.Fa ms
+milliseconds while communicating with
+.Fa dev .
+If a timeout occurs, the corresponding
+.Em fido_dev_*
+function will fail with
+.Dv FIDO_ERR_RX .
+If
+.Fa ms
+is -1,
+then
+.Em libfido2
+may block indefinitely.
+This is the default behaviour.
+When using the Windows Hello backend,
+.Fa ms
+is used as a guidance and may be overwritten by the platform.
+.Pp
+The
+.Fn fido_dev_set_transport_functions
+function sets the transport functions used by
+.Em libfido2
+to talk to
+.Fa dev .
+While the I/O handlers are responsible for sending and receiving
+transmission units of initialization and continuation packets already
+formatted by
+.Em libfido2 ,
+the transport handlers are responsible for sending and receiving
+the CTAPHID commands and data directly, as defined in the FIDO Client
+to Authenticator Protocol (CTAP) standard.
+They are defined as follows:
+.Bl -tag -width Ds
+.It Vt fido_dev_tx_t
+Receives a device, a CTAPHID command to transmit, a data buffer to
+transmit, and the length of the data buffer.
+On success, 0 is returned.
+On error, -1 is returned.
+.It Vt fido_dev_rx_t
+Receives a device, a CTAPHID command whose response the caller expects
+to receive, a data buffer to receive into, the size of the data buffer
+determining the maximum length of a response, and the maximum number of
+milliseconds to wait for a response.
+On success, the number of bytes read into the data buffer is returned.
+On error, -1 is returned.
+.El
+.Pp
+When transport functions are specified,
+.Em libfido2
+will use them instead of the
+.Dv read
+and
+.Dv write
+functions of the I/O handlers.
+However, the I/O handlers must still be specified to open and close the
+device.
+.Pp
+The
+.Fn fido_dev_io_handle
+function returns the opaque pointer returned by the
+.Dv open
+function of the I/O handlers.
+This is useful mainly for the transport functions, which unlike the I/O
+handlers are passed the
+.Vt fido_dev_t
+pointer instead of the opaque I/O handle.
+.Sh RETURN VALUES
+On success,
+.Fn fido_dev_set_io_functions ,
+.Fn fido_dev_set_transport_functions ,
+.Fn fido_dev_set_sigmask ,
+and
+.Fn fido_dev_set_timeout
+return
+.Dv FIDO_OK .
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr fido_dev_info_manifest 3 ,
+.Xr fido_dev_open 3
+.Rs
+.%D 2021-06-15
+.%O Proposed Standard, Version 2.1
+.%Q FIDO Alliance
+.%R Client to Authenticator Protocol (CTAP)
+.%U https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html
+.Re
diff --git a/man/fido_dev_set_pin.3 b/man/fido_dev_set_pin.3
new file mode 100644
index 0000000..eec062d
--- /dev/null
+++ b/man/fido_dev_set_pin.3
@@ -0,0 +1,128 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 25 2018 $
+.Dt FIDO_DEV_SET_PIN 3
+.Os
+.Sh NAME
+.Nm fido_dev_set_pin ,
+.Nm fido_dev_get_retry_count ,
+.Nm fido_dev_get_uv_retry_count ,
+.Nm fido_dev_reset
+.Nd FIDO2 device management functions
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_set_pin "fido_dev_t *dev" "const char *pin" "const char *oldpin"
+.Ft int
+.Fn fido_dev_get_retry_count "fido_dev_t *dev" "int *retries"
+.Ft int
+.Fn fido_dev_get_uv_retry_count "fido_dev_t *dev" "int *retries"
+.Ft int
+.Fn fido_dev_reset "fido_dev_t *dev"
+.Sh DESCRIPTION
+The
+.Fn fido_dev_set_pin
+function sets the PIN of device
+.Fa dev
+to
+.Fa pin ,
+where
+.Fa pin
+is a NUL-terminated UTF-8 string.
+If
+.Fa oldpin
+is not NULL, the device's PIN is changed from
+.Fa oldpin
+to
+.Fa pin ,
+where
+.Fa pin
+and
+.Fa oldpin
+are NUL-terminated UTF-8 strings.
+.Pp
+The
+.Fn fido_dev_get_retry_count
+function fills
+.Fa retries
+with the number of PIN retries left in
+.Fa dev
+before lock-out, where
+.Fa retries
+is an addressable pointer.
+.Pp
+The
+.Fn fido_dev_get_uv_retry_count
+function fills
+.Fa retries
+with the number of built-in UV retries left in
+.Fa dev
+before built-in UV is disabled, where
+.Fa retries
+is an addressable pointer.
+.Pp
+The
+.Fn fido_dev_reset
+function performs a reset on
+.Fa dev ,
+resetting the device's PIN and erasing credentials stored on the
+device.
+.Pp
+Please note that
+.Fn fido_dev_set_pin ,
+.Fn fido_dev_get_retry_count ,
+.Fn fido_dev_get_uv_retry_count ,
+and
+.Fn fido_dev_reset
+are synchronous and will block if necessary.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_set_pin ,
+.Fn fido_dev_get_retry_count ,
+.Fn fido_dev_get_uv_retry_count ,
+and
+.Fn fido_dev_reset
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh SEE ALSO
+.Xr fido_cbor_info_uv_attempts 3
+.Sh CAVEATS
+Regarding
+.Fn fido_dev_reset ,
+the actual user-flow to perform a reset is outside the scope of the
+FIDO2 specification, and may therefore vary depending on the
+authenticator.
+Yubico authenticators will return
+.Dv FIDO_ERR_NOT_ALLOWED
+if a reset is issued later than 5 seconds after power-up, and
+.Dv FIDO_ERR_ACTION_TIMEOUT
+if the user fails to confirm the reset by touching the key
+within 30 seconds.
diff --git a/man/fido_init.3 b/man/fido_init.3
new file mode 100644
index 0000000..12437e1
--- /dev/null
+++ b/man/fido_init.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 25 2018 $
+.Dt FIDO_INIT 3
+.Os
+.Sh NAME
+.Nm fido_init ,
+.Nm fido_set_log_handler
+.Nd initialise the FIDO2 library
+.Sh SYNOPSIS
+.In fido.h
+.Bd -literal
+typedef void fido_log_handler_t(const char *);
+.Ed
+.Pp
+.Ft void
+.Fn fido_init "int flags"
+.Ft void
+.Fn fido_set_log_handler "fido_log_handler_t *handler"
+.Sh DESCRIPTION
+The
+.Fn fido_init
+function initialises the
+.Em libfido2
+library.
+Its invocation must precede that of any other
+.Em libfido2
+function in the context of the executing thread.
+.Pp
+If
+.Dv FIDO_DEBUG
+is set in
+.Fa flags ,
+then
+debug output will be emitted by
+.Em libfido2
+on
+.Em stderr .
+Alternatively, the
+.Ev FIDO_DEBUG
+environment variable may be set.
+.Pp
+If
+.Dv FIDO_DISABLE_U2F_FALLBACK
+is set in
+.Fa flags ,
+then
+.Em libfido2
+will not fallback to U2F in
+.Xr fido_dev_open 3
+if a device claims to support FIDO2 but fails to respond to
+a CTAP 2.0 greeting.
+.Pp
+The
+.Fn fido_set_log_handler
+function causes
+.Fa handler
+to be called for each log line generated in the context of the
+executing thread.
+Lines passed to
+.Fa handler
+include a trailing newline character and are not printed by
+.Em libfido2
+on
+.Em stderr .
+.Sh SEE ALSO
+.Xr fido_assert_new 3 ,
+.Xr fido_cred_new 3 ,
+.Xr fido_dev_info_manifest 3 ,
+.Xr fido_dev_open 3
diff --git a/man/fido_strerr.3 b/man/fido_strerr.3
new file mode 100644
index 0000000..94b48bd
--- /dev/null
+++ b/man/fido_strerr.3
@@ -0,0 +1,50 @@
+.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: May 25 2018 $
+.Dt FIDO_STRERR 3
+.Os
+.Sh NAME
+.Nm fido_strerr
+.Nd FIDO2 error codes
+.Sh SYNOPSIS
+.In fido.h
+.Ft const char *
+.Fn fido_strerr "int n"
+.Sh DESCRIPTION
+The
+.Fn fido_strerr
+function translates the error code
+.Fa n
+into a readable string,
+where
+.Fa n
+is an error code defined in
+.In fido/err.h .
+.Fn fido_strerr
+never returns NULL.
+Returned pointers point to static strings.
diff --git a/man/rs256_pk_new.3 b/man/rs256_pk_new.3
new file mode 100644
index 0000000..0c0ab78
--- /dev/null
+++ b/man/rs256_pk_new.3
@@ -0,0 +1,160 @@
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd $Mdocdate: July 15 2022 $
+.Dt RS256_PK_NEW 3
+.Os
+.Sh NAME
+.Nm rs256_pk_new ,
+.Nm rs256_pk_free ,
+.Nm rs256_pk_from_RSA ,
+.Nm rs256_pk_from_EVP_PKEY ,
+.Nm rs256_pk_from_ptr ,
+.Nm rs256_pk_to_EVP_PKEY
+.Nd FIDO2 COSE RS256 API
+.Sh SYNOPSIS
+.In openssl/rsa.h
+.In fido/rs256.h
+.Ft rs256_pk_t *
+.Fn rs256_pk_new "void"
+.Ft void
+.Fn rs256_pk_free "rs256_pk_t **pkp"
+.Ft int
+.Fn rs256_pk_from_EVP_PKEY "rs256_pk_t *pk" "const EVP_PKEY *pkey"
+.Ft int
+.Fn rs256_pk_from_RSA "rs256_pk_t *pk" "const RSA *rsa"
+.Ft int
+.Fn rs256_pk_from_ptr "rs256_pk_t *pk" "const void *ptr" "size_t len"
+.Ft EVP_PKEY *
+.Fn rs256_pk_to_EVP_PKEY "const rs256_pk_t *pk"
+.Sh DESCRIPTION
+RS256 is the name given in the CBOR Object Signing and Encryption
+(COSE) RFC to PKCS#1.5 2048-bit RSA with SHA-256.
+The COSE RS256 API of
+.Em libfido2
+is an auxiliary API with routines to convert between the different
+RSA public key types used in
+.Em libfido2
+and
+.Em OpenSSL .
+.Pp
+In
+.Em libfido2 ,
+RS256 public keys are abstracted by the
+.Vt rs256_pk_t
+type.
+.Pp
+The
+.Fn rs256_pk_new
+function returns a pointer to a newly allocated, empty
+.Vt rs256_pk_t
+type.
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
+.Fn rs256_pk_free
+function releases the memory backing
+.Fa *pkp ,
+where
+.Fa *pkp
+must have been previously allocated by
+.Fn rs256_pk_new .
+On return,
+.Fa *pkp
+is set to NULL.
+Either
+.Fa pkp
+or
+.Fa *pkp
+may be NULL, in which case
+.Fn rs256_pk_free
+is a NOP.
+.Pp
+The
+.Fn rs256_pk_from_EVP_PKEY
+function fills
+.Fa pk
+with the contents of
+.Fa pkey .
+No references to
+.Fa pkey
+are kept.
+.Pp
+The
+.Fn rs256_pk_from_RSA
+function fills
+.Fa pk
+with the contents of
+.Fa rsa .
+No references to
+.Fa rsa
+are kept.
+.Pp
+The
+.Fn rs256_pk_from_ptr
+function fills
+.Fa pk
+with the contents of
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+No references to
+.Fa ptr
+are kept.
+.Pp
+The
+.Fn rs256_pk_to_EVP_PKEY
+function converts
+.Fa pk
+to a newly allocated
+.Fa EVP_PKEY
+type with a reference count of 1.
+No internal references to the returned pointer are kept.
+If an error occurs,
+.Fn rs256_pk_to_EVP_PKEY
+returns NULL.
+.Sh RETURN VALUES
+The
+.Fn rs256_pk_from_EVP_PKEY ,
+.Fn rs256_pk_from_RSA ,
+and
+.Fn rs256_pk_from_ptr
+functions return
+.Dv FIDO_OK
+on success.
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Sh SEE ALSO
+.Xr eddsa_pk_new 3 ,
+.Xr es256_pk_new 3 ,
+.Xr es384_pk_new 3 ,
+.Xr fido_assert_verify 3 ,
+.Xr fido_cred_pubkey_ptr 3
diff --git a/man/style.css b/man/style.css
new file mode 100644
index 0000000..8c223fa
--- /dev/null
+++ b/man/style.css
@@ -0,0 +1,24 @@
+* { margin: 0; padding: 0; }
+
+body {
+ font-family: monospace;
+ font-size: 1em;
+ margin: 2% auto;
+ max-width: 54em;
+}
+
+ul { margin-left: 1em; }
+a { color: #009900; }
+.Sh { font-size: 1em; padding-top: 1em; padding-bottom: 1em; }
+.foot { padding-top: 1em; }
+
+table.head, table.foot { width: 100%; }
+td.head-rtitle, td.foot-os { text-align: right; }
+td.head-vol { text-align: center; }
+div.Pp { margin: 1ex 0ex; }
+div.Nd, div.Bf, div.Op { display: inline; }
+span.Pa, span.Ad { font-style: italic; }
+span.Ms { font-weight: bold; }
+dl.Bl-diag > dt { font-weight: bold; }
+code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn,
+code.Cd { font-weight: bold; font-family: inherit; }
diff --git a/openbsd-compat/bsd-asprintf.c b/openbsd-compat/bsd-asprintf.c
new file mode 100644
index 0000000..fbcb867
--- /dev/null
+++ b/openbsd-compat/bsd-asprintf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.
+ *
+ * Based originally on asprintf.c from OpenBSD:
+ * Copyright (c) 1997 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "openbsd-compat.h"
+
+#ifndef HAVE_ASPRINTF
+
+#include
+#include /* for INT_MAX */
+#include
+#include /* for vsnprintf */
+#include
+
+#define VA_COPY(dest, src) va_copy(dest, src)
+
+#define INIT_SZ 128
+
+int
+vasprintf(char **str, const char *fmt, va_list ap)
+{
+ int ret;
+ va_list ap2;
+ char *string, *newstr;
+ size_t len;
+
+ if ((string = malloc(INIT_SZ)) == NULL)
+ goto fail;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+ va_end(ap2);
+ if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
+ *str = string;
+ } else if (ret == INT_MAX || ret < 0) { /* Bad length */
+ free(string);
+ goto fail;
+ } else { /* bigger than initial, realloc allowing for nul */
+ len = (size_t)ret + 1;
+ if ((newstr = realloc(string, len)) == NULL) {
+ free(string);
+ goto fail;
+ }
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(newstr, len, fmt, ap2);
+ va_end(ap2);
+ if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */
+ free(newstr);
+ goto fail;
+ }
+ *str = newstr;
+ }
+ return (ret);
+
+fail:
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+}
+
+int asprintf(char **str, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ *str = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(str, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
diff --git a/openbsd-compat/bsd-getline.c b/openbsd-compat/bsd-getline.c
new file mode 100644
index 0000000..52b44f7
--- /dev/null
+++ b/openbsd-compat/bsd-getline.c
@@ -0,0 +1,115 @@
+/* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */
+
+/* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */
+
+#include "openbsd-compat.h"
+
+#if 0
+#include "file.h"
+#endif
+
+#if !HAVE_GETLINE
+#include
+#include
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#include
+#include
+
+static ssize_t
+getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
+{
+ char *ptr, *eptr;
+
+
+ if (*buf == NULL || *bufsiz == 0) {
+ if ((*buf = malloc(BUFSIZ)) == NULL)
+ return -1;
+ *bufsiz = BUFSIZ;
+ }
+
+ for (ptr = *buf, eptr = *buf + *bufsiz;;) {
+ int c = fgetc(fp);
+ if (c == -1) {
+ if (feof(fp)) {
+ ssize_t diff = (ssize_t)(ptr - *buf);
+ if (diff != 0) {
+ *ptr = '\0';
+ return diff;
+ }
+ }
+ return -1;
+ }
+ *ptr++ = (char)c;
+ if (c == delimiter) {
+ *ptr = '\0';
+ return ptr - *buf;
+ }
+ if (ptr + 2 >= eptr) {
+ char *nbuf;
+ size_t nbufsiz = *bufsiz * 2;
+ ssize_t d = ptr - *buf;
+ if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
+ return -1;
+ *buf = nbuf;
+ *bufsiz = nbufsiz;
+ eptr = nbuf + nbufsiz;
+ ptr = nbuf + d;
+ }
+ }
+}
+
+ssize_t
+getline(char **buf, size_t *bufsiz, FILE *fp)
+{
+ return getdelim(buf, bufsiz, '\n', fp);
+}
+
+#endif
+
+#ifdef TEST
+int
+main(int argc, char *argv[])
+{
+ char *p = NULL;
+ ssize_t len;
+ size_t n = 0;
+
+ while ((len = getline(&p, &n, stdin)) != -1)
+ (void)printf("%" SIZE_T_FORMAT "d %s", len, p);
+ free(p);
+ return 0;
+}
+#endif
diff --git a/openbsd-compat/bsd-getpagesize.c b/openbsd-compat/bsd-getpagesize.c
new file mode 100644
index 0000000..903bfc3
--- /dev/null
+++ b/openbsd-compat/bsd-getpagesize.c
@@ -0,0 +1,27 @@
+/* Placed in the public domain */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_GETPAGESIZE)
+
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#include
+
+int
+getpagesize(void)
+{
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+ long r = sysconf(_SC_PAGESIZE);
+ if (r > 0 && r < INT_MAX)
+ return (int)r;
+#endif
+ /*
+ * This is at the lower end of common values and appropriate for
+ * our current use of getpagesize() in recallocarray().
+ */
+ return 4096;
+}
+
+#endif /* !defined(HAVE_GETPAGESIZE) */
diff --git a/openbsd-compat/clock_gettime.c b/openbsd-compat/clock_gettime.c
new file mode 100644
index 0000000..bbf978c
--- /dev/null
+++ b/openbsd-compat/clock_gettime.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_CLOCK_GETTIME)
+
+#if _WIN32
+int
+clock_gettime(clockid_t clock_id, struct timespec *tp)
+{
+ ULONGLONG ms;
+
+ if (clock_id != CLOCK_MONOTONIC) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ms = GetTickCount64();
+ tp->tv_sec = ms / 1000L;
+ tp->tv_nsec = (ms % 1000L) * 1000000L;
+
+ return (0);
+}
+#else
+#error "please provide an implementation of clock_gettime() for your platform"
+#endif /* _WIN32 */
+
+#endif /* !defined(HAVE_CLOCK_GETTIME) */
diff --git a/openbsd-compat/endian_win32.c b/openbsd-compat/endian_win32.c
new file mode 100644
index 0000000..756c0cb
--- /dev/null
+++ b/openbsd-compat/endian_win32.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "openbsd-compat.h"
+
+#if defined(_WIN32) && !defined(HAVE_ENDIAN_H)
+
+/*
+ * Hopefully, if the endianness differs from the end result, the compiler
+ * optimizes these functions with some type of bswap instruction. Or,
+ * otherwise, to just return the input value unmodified. GCC and clang
+ * both does these optimization at least. This should be preferred over
+ * relying on some BYTE_ORDER macro, which may or may not be defined.
+ */
+
+uint32_t
+htole32(uint32_t in)
+{
+ uint32_t out = 0;
+ uint8_t *b = (uint8_t *)&out;
+
+ b[0] = (uint8_t)((in >> 0) & 0xff);
+ b[1] = (uint8_t)((in >> 8) & 0xff);
+ b[2] = (uint8_t)((in >> 16) & 0xff);
+ b[3] = (uint8_t)((in >> 24) & 0xff);
+
+ return (out);
+}
+
+uint64_t
+htole64(uint64_t in)
+{
+ uint64_t out = 0;
+ uint8_t *b = (uint8_t *)&out;
+
+ b[0] = (uint8_t)((in >> 0) & 0xff);
+ b[1] = (uint8_t)((in >> 8) & 0xff);
+ b[2] = (uint8_t)((in >> 16) & 0xff);
+ b[3] = (uint8_t)((in >> 24) & 0xff);
+ b[4] = (uint8_t)((in >> 32) & 0xff);
+ b[5] = (uint8_t)((in >> 40) & 0xff);
+ b[6] = (uint8_t)((in >> 48) & 0xff);
+ b[7] = (uint8_t)((in >> 56) & 0xff);
+
+ return (out);
+}
+
+#endif /* WIN32 && !HAVE_ENDIAN_H */
diff --git a/openbsd-compat/err.h b/openbsd-compat/err.h
new file mode 100644
index 0000000..394c7bb
--- /dev/null
+++ b/openbsd-compat/err.h
@@ -0,0 +1,85 @@
+/*
+ * Public domain
+ * err.h compatibility shim
+ */
+
+#ifndef _COMPAT_ERR_H
+#define _COMPAT_ERR_H
+
+#if !defined(HAVE_ERR_H)
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(_MSC_VER)
+__declspec(noreturn)
+#else
+__attribute__((noreturn))
+#endif
+static inline void
+err(int eval, const char *fmt, ...)
+{
+ int sverrno = errno;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ va_end(ap);
+ fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(eval);
+}
+
+#if defined(_MSC_VER)
+__declspec(noreturn)
+#else
+__attribute__((noreturn))
+#endif
+static inline void
+errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(eval);
+}
+
+static inline void
+warn(const char *fmt, ...)
+{
+ int sverrno = errno;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ va_end(ap);
+ fprintf(stderr, "%s\n", strerror(sverrno));
+}
+
+static inline void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+#endif /* !defined(HAVE_ERR_H) */
+
+#endif /* _COMPAT_ERR_H */
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
new file mode 100644
index 0000000..ac64e69
--- /dev/null
+++ b/openbsd-compat/explicit_bzero.c
@@ -0,0 +1,57 @@
+/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */
+/* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */
+/*
+ * Public domain.
+ * Written by Ted Unangst
+ */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32)
+
+#include
+
+/*
+ * explicit_bzero - don't let the compiler optimize away bzero
+ */
+
+#ifdef HAVE_MEMSET_S
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ if (n == 0)
+ return;
+ (void)memset_s(p, n, 0, n);
+}
+
+#else /* HAVE_MEMSET_S */
+
+/*
+ * Indirect bzero through a volatile pointer to hopefully avoid
+ * dead-store optimisation eliminating the call.
+ */
+static void (* volatile ssh_bzero)(void *, size_t) = bzero;
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ if (n == 0)
+ return;
+ /*
+ * clang -fsanitize=memory needs to intercept memset-like functions
+ * to correctly detect memory initialisation. Make sure one is called
+ * directly since our indirection trick above successfully confuses it.
+ */
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+ memset(p, 0, n);
+# endif
+#endif
+
+ ssh_bzero(p, n);
+}
+
+#endif /* HAVE_MEMSET_S */
+
+#endif /* !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) */
diff --git a/openbsd-compat/explicit_bzero_win32.c b/openbsd-compat/explicit_bzero_win32.c
new file mode 100644
index 0000000..8017aff
--- /dev/null
+++ b/openbsd-compat/explicit_bzero_win32.c
@@ -0,0 +1,19 @@
+/*
+ * Public domain.
+ * Win32 explicit_bzero compatibility shim.
+ */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32)
+
+#include
+#include
+
+void
+explicit_bzero(void *buf, size_t len)
+{
+ SecureZeroMemory(buf, len);
+}
+
+#endif /* !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32) */
diff --git a/openbsd-compat/freezero.c b/openbsd-compat/freezero.c
new file mode 100644
index 0000000..d1e0066
--- /dev/null
+++ b/openbsd-compat/freezero.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "openbsd-compat.h"
+
+#ifndef HAVE_FREEZERO
+
+void
+freezero(void *ptr, size_t sz)
+{
+ if (ptr == NULL)
+ return;
+ explicit_bzero(ptr, sz);
+ free(ptr);
+}
+
+#endif /* HAVE_FREEZERO */
diff --git a/openbsd-compat/getopt.h b/openbsd-compat/getopt.h
new file mode 100644
index 0000000..8eb1244
--- /dev/null
+++ b/openbsd-compat/getopt.h
@@ -0,0 +1,74 @@
+/* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */
+/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+/*
+ * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
+ */
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+struct option {
+ /* name of long option */
+ const char *name;
+ /*
+ * one of no_argument, required_argument, and optional_argument:
+ * whether option takes an argument
+ */
+ int has_arg;
+ /* if not NULL, set *flag to val when option found */
+ int *flag;
+ /* if flag not NULL, value to set *flag to; else return value */
+ int val;
+};
+
+int getopt_long(int, char * const *, const char *,
+ const struct option *, int *);
+int getopt_long_only(int, char * const *, const char *,
+ const struct option *, int *);
+#ifndef _GETOPT_DEFINED_
+#define _GETOPT_DEFINED_
+int getopt(int, char * const *, const char *);
+int getsubopt(char **, char * const *, char **);
+
+extern char *optarg; /* getopt(3) external variables */
+extern int opterr;
+extern int optind;
+extern int optopt;
+extern int optreset;
+extern char *suboptarg; /* getsubopt(3) external variable */
+#endif
+
+#endif /* !_GETOPT_H_ */
diff --git a/openbsd-compat/getopt_long.c b/openbsd-compat/getopt_long.c
new file mode 100644
index 0000000..dabbb46
--- /dev/null
+++ b/openbsd-compat/getopt_long.c
@@ -0,0 +1,523 @@
+/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_GETOPT)
+
+#if 0
+#include
+#include
+#endif
+#include
+#include
+#include
+#include
+
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, match;
+
+ current_argv = place;
+ match = -1;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1 || optreset)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+
+#if 0
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
+#endif
+
+#endif /* !defined(HAVE_GETOPT) */
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
new file mode 100644
index 0000000..9f1ea3e
--- /dev/null
+++ b/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _OPENBSD_COMPAT_H
+#define _OPENBSD_COMPAT_H
+
+#if defined(_MSC_VER)
+#include "types.h"
+#endif
+
+#if defined(HAVE_ENDIAN_H)
+#include
+#endif
+
+#if defined(__APPLE__) && !defined(HAVE_ENDIAN_H)
+#include
+#define be16toh(x) OSSwapBigToHostInt16((x))
+#define htobe16(x) OSSwapHostToBigInt16((x))
+#define be32toh(x) OSSwapBigToHostInt32((x))
+#define htobe32(x) OSSwapHostToBigInt32((x))
+#define htole32(x) OSSwapHostToLittleInt32((x))
+#define htole64(x) OSSwapHostToLittleInt64((x))
+#endif /* __APPLE__ && !HAVE_ENDIAN_H */
+
+#if defined(_WIN32) && !defined(HAVE_ENDIAN_H)
+#include
+#include
+#if !defined(_MSC_VER)
+#include
+#endif
+#define be16toh(x) ntohs((x))
+#define htobe16(x) htons((x))
+#define be32toh(x) ntohl((x))
+#define htobe32(x) htonl((x))
+uint32_t htole32(uint32_t);
+uint64_t htole64(uint64_t);
+#endif /* _WIN32 && !HAVE_ENDIAN_H */
+
+#if (defined(__FreeBSD__) || defined(__MidnightBSD__)) && !defined(HAVE_ENDIAN_H)
+#include
+#endif
+
+#include
+#include
+
+#if !defined(HAVE_STRLCAT)
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#if !defined(HAVE_STRLCPY)
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#if !defined(HAVE_STRSEP)
+char *strsep(char **, const char *);
+#endif
+
+#if !defined(HAVE_RECALLOCARRAY)
+void *recallocarray(void *, size_t, size_t, size_t);
+#endif
+
+#if !defined(HAVE_EXPLICIT_BZERO)
+void explicit_bzero(void *, size_t);
+#endif
+
+#if !defined(HAVE_FREEZERO)
+void freezero(void *, size_t);
+#endif
+
+#if !defined(HAVE_GETPAGESIZE)
+int getpagesize(void);
+#endif
+
+#if !defined(HAVE_TIMINGSAFE_BCMP)
+int timingsafe_bcmp(const void *, const void *, size_t);
+#endif
+
+#if !defined(HAVE_READPASSPHRASE)
+#include "readpassphrase.h"
+#else
+#include
+#endif
+
+#include
+
+#if !defined(HAVE_ERR_H)
+#include "err.h"
+#else
+#include
+#endif
+
+#if !defined(HAVE_GETOPT)
+#include "getopt.h"
+#else
+#include
+#endif
+
+#if !defined(HAVE_GETLINE)
+#include
+ssize_t getline(char **, size_t *, FILE *);
+#endif
+
+#if defined(_MSC_VER)
+#define strerror_r(e, b, l) strerror_s((b), (l), (e))
+#endif
+
+#include "time.h"
+
+#if !defined(HAVE_POSIX_IOCTL)
+#define IOCTL_REQ(x) (x)
+#else
+#define IOCTL_REQ(x) ((int)(x))
+#endif
+
+#if !defined(HAVE_ASPRINTF)
+int asprintf(char **, const char *, ...);
+#endif
+
+#endif /* !_OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/posix_ioctl_check.c b/openbsd-compat/posix_ioctl_check.c
new file mode 100644
index 0000000..599a3bf
--- /dev/null
+++ b/openbsd-compat/posix_ioctl_check.c
@@ -0,0 +1,7 @@
+#include
+
+int
+posix_ioctl_check(int fd)
+{
+ return ioctl(fd, -1, 0);
+}
diff --git a/openbsd-compat/posix_win.c b/openbsd-compat/posix_win.c
new file mode 100644
index 0000000..eac67c2
--- /dev/null
+++ b/openbsd-compat/posix_win.c
@@ -0,0 +1,61 @@
+/*
+ * Public domain
+ *
+ * File IO compatibility shims
+ * Brent Cook
+ */
+
+#define NO_REDEF_POSIX_FUNCTIONS
+
+#include
+
+#include
+#include
+
+#include "posix_win.h"
+
+int
+posix_open(const char *path, ...)
+{
+ va_list ap;
+ int mode = 0;
+ int flags;
+
+ va_start(ap, path);
+ flags = va_arg(ap, int);
+ if (flags & O_CREAT)
+ mode = va_arg(ap, int);
+ va_end(ap);
+
+ flags |= O_BINARY | O_NOINHERIT;
+
+ return (open(path, flags, mode));
+}
+
+int
+posix_close(int fd)
+{
+ return (close(fd));
+}
+
+ssize_t
+posix_read(int fd, void *buf, size_t count)
+{
+ if (count > INT_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (read(fd, buf, (unsigned int)count));
+}
+
+ssize_t
+posix_write(int fd, const void *buf, size_t count)
+{
+ if (count > INT_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (write(fd, buf, (unsigned int)count));
+}
diff --git a/openbsd-compat/posix_win.h b/openbsd-compat/posix_win.h
new file mode 100644
index 0000000..a1e0888
--- /dev/null
+++ b/openbsd-compat/posix_win.h
@@ -0,0 +1,47 @@
+/*
+ * Public domain
+ *
+ * BSD socket emulation code for Winsock2
+ * Brent Cook
+ */
+
+#ifndef _COMPAT_POSIX_WIN_H
+#define _COMPAT_POSIX_WIN_H
+
+#ifdef _WIN32
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if _MSC_VER >= 1900
+#include <../ucrt/fcntl.h>
+#else
+#include <../include/fcntl.h>
+#endif
+
+#include "types.h"
+
+int posix_open(const char *path, ...);
+
+int posix_close(int fd);
+
+ssize_t posix_read(int fd, void *buf, size_t count);
+
+ssize_t posix_write(int fd, const void *buf, size_t count);
+
+#ifndef NO_REDEF_POSIX_FUNCTIONS
+#define open(path, ...) posix_open(path, __VA_ARGS__)
+#define close(fd) posix_close(fd)
+#define read(fd, buf, count) posix_read(fd, buf, count)
+#define write(fd, buf, count) posix_write(fd, buf, count)
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* !_COMPAT_POSIX_WIN_H */
diff --git a/openbsd-compat/readpassphrase.c b/openbsd-compat/readpassphrase.c
new file mode 100644
index 0000000..8b84190
--- /dev/null
+++ b/openbsd-compat/readpassphrase.c
@@ -0,0 +1,214 @@
+/* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */
+
+/*
+ * Copyright (c) 2000-2002, 2007, 2010
+ * Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
+
+#include "openbsd-compat.h"
+
+#ifndef HAVE_READPASSPHRASE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#include
+
+#ifndef _PATH_TTY
+# define _PATH_TTY "/dev/tty"
+#endif
+
+#ifndef TCSASOFT
+/* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */
+# define TCSASOFT 0
+#endif
+
+/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
+#if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
+# define _POSIX_VDISABLE VDISABLE
+#endif
+
+static volatile sig_atomic_t signo[NSIG];
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+ ssize_t nr;
+ int input, output, save_errno, i, need_restart;
+ char ch, *p, *end;
+ struct termios term, oterm;
+ struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
+ struct sigaction savetstp, savettin, savettou, savepipe;
+
+ /* I suppose we could alloc on demand in this case (XXX). */
+ if (bufsiz == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+restart:
+ for (i = 0; i < NSIG; i++)
+ signo[i] = 0;
+ need_restart = 0;
+ /*
+ * Read and write to /dev/tty if available. If not, read from
+ * stdin and write to stderr unless a tty is required.
+ */
+ if ((flags & RPP_STDIN) ||
+ (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
+ if (flags & RPP_REQUIRE_TTY) {
+ errno = ENOTTY;
+ return(NULL);
+ }
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ }
+
+ /*
+ * Turn off echo if possible.
+ * If we are using a tty but are not the foreground pgrp this will
+ * generate SIGTTOU, so do it *before* installing the signal handlers.
+ */
+ if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
+ memcpy(&term, &oterm, sizeof(term));
+ if (!(flags & RPP_ECHO_ON))
+ term.c_lflag &= ~(ECHO | ECHONL);
+#ifdef VSTATUS
+ if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
+ term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+#endif
+ (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
+ } else {
+ memset(&term, 0, sizeof(term));
+ term.c_lflag |= ECHO;
+ memset(&oterm, 0, sizeof(oterm));
+ oterm.c_lflag |= ECHO;
+ }
+
+ /*
+ * Catch signals that would otherwise cause the user to end
+ * up with echo turned off in the shell. Don't worry about
+ * things like SIGXCPU and SIGVTALRM for now.
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; /* don't restart system calls */
+ sa.sa_handler = handler;
+ (void)sigaction(SIGALRM, &sa, &savealrm);
+ (void)sigaction(SIGHUP, &sa, &savehup);
+ (void)sigaction(SIGINT, &sa, &saveint);
+ (void)sigaction(SIGPIPE, &sa, &savepipe);
+ (void)sigaction(SIGQUIT, &sa, &savequit);
+ (void)sigaction(SIGTERM, &sa, &saveterm);
+ (void)sigaction(SIGTSTP, &sa, &savetstp);
+ (void)sigaction(SIGTTIN, &sa, &savettin);
+ (void)sigaction(SIGTTOU, &sa, &savettou);
+
+ if (!(flags & RPP_STDIN))
+ (void)write(output, prompt, strlen(prompt));
+ end = buf + bufsiz - 1;
+ p = buf;
+ while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
+ if (p < end) {
+ if ((flags & RPP_SEVENBIT))
+ ch &= 0x7f;
+ if (isalpha((unsigned char)ch)) {
+ if ((flags & RPP_FORCELOWER))
+ ch = (char)tolower((unsigned char)ch);
+ if ((flags & RPP_FORCEUPPER))
+ ch = (char)toupper((unsigned char)ch);
+ }
+ *p++ = ch;
+ }
+ }
+ *p = '\0';
+ save_errno = errno;
+ if (!(term.c_lflag & ECHO))
+ (void)write(output, "\n", 1);
+
+ /* Restore old terminal settings and signals. */
+ if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+ const int sigttou = signo[SIGTTOU];
+
+ /* Ignore SIGTTOU generated when we are not the fg pgrp. */
+ while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
+ errno == EINTR && !signo[SIGTTOU])
+ continue;
+ signo[SIGTTOU] = sigttou;
+ }
+ (void)sigaction(SIGALRM, &savealrm, NULL);
+ (void)sigaction(SIGHUP, &savehup, NULL);
+ (void)sigaction(SIGINT, &saveint, NULL);
+ (void)sigaction(SIGQUIT, &savequit, NULL);
+ (void)sigaction(SIGPIPE, &savepipe, NULL);
+ (void)sigaction(SIGTERM, &saveterm, NULL);
+ (void)sigaction(SIGTSTP, &savetstp, NULL);
+ (void)sigaction(SIGTTIN, &savettin, NULL);
+ (void)sigaction(SIGTTOU, &savettou, NULL);
+ if (input != STDIN_FILENO)
+ (void)close(input);
+
+ /*
+ * If we were interrupted by a signal, resend it to ourselves
+ * now that we have restored the signal handlers.
+ */
+ for (i = 0; i < NSIG; i++) {
+ if (signo[i]) {
+ kill(getpid(), i);
+ switch (i) {
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ need_restart = 1;
+ }
+ }
+ }
+ if (need_restart)
+ goto restart;
+
+ if (save_errno)
+ errno = save_errno;
+ return(nr == -1 ? NULL : buf);
+}
+
+#if 0
+char *
+getpass(const char *prompt)
+{
+ static char buf[_PASSWORD_LEN + 1];
+
+ return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
+}
+#endif
+
+static void handler(int s)
+{
+
+ signo[s] = 1;
+}
+#endif /* HAVE_READPASSPHRASE */
diff --git a/openbsd-compat/readpassphrase.h b/openbsd-compat/readpassphrase.h
new file mode 100644
index 0000000..e4451f3
--- /dev/null
+++ b/openbsd-compat/readpassphrase.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */
+
+/*
+ * Copyright (c) 2000, 2002 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/* OPENBSD ORIGINAL: include/readpassphrase.h */
+
+#ifndef _READPASSPHRASE_H_
+#define _READPASSPHRASE_H_
+
+#ifndef HAVE_READPASSPHRASE
+
+#include
+
+#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
+#define RPP_ECHO_ON 0x01 /* Leave echo on. */
+#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
+#define RPP_FORCELOWER 0x04 /* Force input to lower case. */
+#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
+#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
+#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */
+
+char * readpassphrase(const char *, char *, size_t, int);
+
+#endif /* HAVE_READPASSPHRASE */
+
+#endif /* !_READPASSPHRASE_H_ */
diff --git a/openbsd-compat/readpassphrase_win32.c b/openbsd-compat/readpassphrase_win32.c
new file mode 100644
index 0000000..968987c
--- /dev/null
+++ b/openbsd-compat/readpassphrase_win32.c
@@ -0,0 +1,131 @@
+/*
+* Author: Manoj Ampalam
+*
+* Author: Bryan Berns
+* Modified group detection use s4u token information
+*
+* Copyright(c) 2016 Microsoft Corp.
+* All rights reserved
+*
+* Misc Unix POSIX routine implementations for Windows
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met :
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and / or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define UMDF_USING_NTSTATUS
+#define SECURITY_WIN32
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "openbsd-compat.h"
+
+#ifndef HAVE_READPASSPHRASE
+
+/*on error returns NULL and sets errno*/
+static wchar_t *
+utf8_to_utf16(const char *utf8)
+{
+ int needed = 0;
+ wchar_t* utf16 = NULL;
+ if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 ||
+ (utf16 = malloc(needed * sizeof(wchar_t))) == NULL ||
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) {
+ /* debug3("failed to convert utf8 payload:%s error:%d", utf8, GetLastError()); */
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return utf16;
+}
+
+char *
+readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
+{
+ size_t current_index = 0;
+ char ch;
+ wchar_t* wtmp = NULL;
+
+ if (outBufLen == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ while (_kbhit()) (void)_getch();
+
+ wtmp = utf8_to_utf16(prompt);
+ if (wtmp == NULL)
+ errx(1, "unable to alloc memory");
+
+ _cputws(wtmp);
+ free(wtmp);
+
+ while (current_index < outBufLen - 1) {
+ ch = (char)_getch();
+
+ if (ch == '\r') {
+ if (_kbhit()) (void)_getch(); /* read linefeed if its there */
+ break;
+ } else if (ch == '\n') {
+ break;
+ } else if (ch == '\b') { /* backspace */
+ if (current_index > 0) {
+ if (flags & RPP_ECHO_ON)
+ printf_s("%c \b", ch);
+
+ current_index--; /* overwrite last character */
+ }
+ } else if (ch == '\003') { /* exit on Ctrl+C */
+ errx(1, "");
+ } else {
+ if (flags & RPP_SEVENBIT)
+ ch &= 0x7f;
+
+ if (isalpha((unsigned char)ch)) {
+ if(flags & RPP_FORCELOWER)
+ ch = (char)tolower((unsigned char)ch);
+ if(flags & RPP_FORCEUPPER)
+ ch = (char)toupper((unsigned char)ch);
+ }
+
+ outBuf[current_index++] = ch;
+ if(flags & RPP_ECHO_ON)
+ printf_s("%c", ch);
+ }
+ }
+
+ outBuf[current_index] = '\0';
+ _cputs("\n");
+
+ return outBuf;
+}
+
+#endif /* HAVE_READPASSPHRASE */
diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c
new file mode 100644
index 0000000..5d2f8d9
--- /dev/null
+++ b/openbsd-compat/recallocarray.c
@@ -0,0 +1,91 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_RECALLOCARRAY)
+
+#include
+#include
+#include
+#include
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
+/* DEF_WEAK(recallocarray); */
+
+#endif /* !defined(HAVE_RECALLOCARRAY) */
diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c
new file mode 100644
index 0000000..44470de
--- /dev/null
+++ b/openbsd-compat/strlcat.c
@@ -0,0 +1,63 @@
+/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_STRLCAT)
+
+#include
+#include
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+#endif /* !defined(HAVE_STRLCAT) */
diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c
new file mode 100644
index 0000000..a8b18ea
--- /dev/null
+++ b/openbsd-compat/strlcpy.c
@@ -0,0 +1,59 @@
+/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_STRLCPY)
+
+#include
+#include
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+#endif /* !defined(HAVE_STRLCPY) */
diff --git a/openbsd-compat/strsep.c b/openbsd-compat/strsep.c
new file mode 100644
index 0000000..578668c
--- /dev/null
+++ b/openbsd-compat/strsep.c
@@ -0,0 +1,79 @@
+/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_STRSEP)
+
+#include
+#include
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+#endif /* !defined(HAVE_STRSEP) */
diff --git a/openbsd-compat/time.h b/openbsd-compat/time.h
new file mode 100644
index 0000000..b125f73
--- /dev/null
+++ b/openbsd-compat/time.h
@@ -0,0 +1,61 @@
+/*
+ * Public domain
+ * sys/time.h compatibility shim
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+#include <../ucrt/time.h>
+#elif defined(_MSC_VER) && (_MSC_VER < 1900)
+#include <../include/time.h>
+#else
+#include
+#endif
+
+#ifndef _COMPAT_TIME_H
+#define _COMPAT_TIME_H
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC CLOCK_REALTIME
+#endif
+
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+#endif
+
+#ifndef HAVE_CLOCK_GETTIME
+typedef int clockid_t;
+int clock_gettime(clockid_t, struct timespec *);
+#endif
+
+#ifdef HAVE_TIMESPECSUB
+#include
+#endif
+
+#ifndef HAVE_TIMESPECSUB
+#define timespecadd(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec >= 1000000000L) { \
+ (vsp)->tv_sec++; \
+ (vsp)->tv_nsec -= 1000000000L; \
+ } \
+ } while (0)
+
+#define timespecsub(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (0)
+
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif
+
+#endif /* _COMPAT_TIME_H */
diff --git a/openbsd-compat/timingsafe_bcmp.c b/openbsd-compat/timingsafe_bcmp.c
new file mode 100644
index 0000000..3f7b9e5
--- /dev/null
+++ b/openbsd-compat/timingsafe_bcmp.c
@@ -0,0 +1,35 @@
+/* $OpenBSD: timingsafe_bcmp.c,v 1.1 2010/09/24 13:33:00 matthew Exp $ */
+/*
+ * Copyright (c) 2010 Damien Miller. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/timingsafe_bcmp.c */
+
+#include "openbsd-compat.h"
+
+#if !defined(HAVE_TIMINGSAFE_BCMP)
+
+int
+timingsafe_bcmp(const void *b1, const void *b2, size_t n)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ int ret = 0;
+
+ for (; n > 0; n--)
+ ret |= *p1++ ^ *p2++;
+ return (ret != 0);
+}
+
+#endif /* !defined(HAVE_TIMINGSAFE_BCMP) */
diff --git a/openbsd-compat/types.h b/openbsd-compat/types.h
new file mode 100644
index 0000000..6170230
--- /dev/null
+++ b/openbsd-compat/types.h
@@ -0,0 +1,69 @@
+/*
+ * Public domain
+ * sys/types.h compatibility shim
+ */
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1900
+#include <../ucrt/sys/types.h>
+#else
+#include <../include/sys/types.h>
+#endif
+#endif
+
+#ifndef _COMPAT_TYPES_H
+#define _COMPAT_TYPES_H
+
+#include
+
+#ifdef __MINGW32__
+#include <_bsd_types.h>
+typedef uint32_t in_addr_t;
+typedef uint32_t uid_t;
+#endif
+
+#ifdef _MSC_VER
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+#include
+typedef SSIZE_T ssize_t;
+
+#ifndef SSIZE_MAX
+#ifdef _WIN64
+#define SSIZE_MAX _I64_MAX
+#else
+#define SSIZE_MAX INT_MAX
+#endif
+#endif
+
+#endif
+
+#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__)
+# define __bounded__(x, y, z)
+#endif
+
+#ifdef _WIN32
+#define __warn_references(sym,msg)
+#else
+
+#ifndef __warn_references
+
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG)
+#define __warn_references(sym,msg) \
+ __asm__(".section .gnu.warning." __STRING(sym) \
+ "\n\t.ascii \"" msg "\"\n\t.text");
+#else
+#define __warn_references(sym,msg)
+#endif
+
+#endif /* __warn_references */
+#endif /* _WIN32 */
+
+#endif /* !_COMPAT_TYPES_H */
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt
new file mode 100644
index 0000000..246bffa
--- /dev/null
+++ b/regress/CMakeLists.txt
@@ -0,0 +1,57 @@
+# Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+add_custom_target(regress)
+
+macro(add_regress_test NAME SOURCES LIB)
+ add_executable(${NAME} ${SOURCES})
+ add_test(${NAME} ${NAME})
+ add_dependencies(regress ${NAME})
+ target_link_libraries(${NAME} ${LIB})
+endmacro()
+
+if(MSVC AND BUILD_SHARED_LIBS)
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E copy
+ "${CBOR_BIN_DIRS}/${CBOR_LIBRARIES}.dll"
+ "${CRYPTO_BIN_DIRS}/${CRYPTO_LIBRARIES}.dll"
+ "${ZLIB_BIN_DIRS}/${ZLIB_LIBRARIES}.dll"
+ "$"
+ "${CMAKE_CURRENT_BINARY_DIR}")
+endif()
+
+if(CYGWIN AND BUILD_SHARED_LIBS)
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E copy
+ "$"
+ "${CMAKE_CURRENT_BINARY_DIR}")
+endif()
+
+if(CMAKE_CROSSCOMPILING OR (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64" AND
+ CMAKE_GENERATOR_PLATFORM MATCHES "^ARM.*$"))
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E echo
+ "Cross-compilation detected. Skipping regress tests.")
+else()
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
+endif()
+
+add_regress_test(regress_assert assert.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_cred cred.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_dev dev.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_eddsa eddsa.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_es256 es256.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_es384 es384.c ${_FIDO2_LIBRARY})
+add_regress_test(regress_rs256 rs256.c ${_FIDO2_LIBRARY})
+if(BUILD_STATIC_LIBS)
+ add_regress_test(regress_compress compress.c fido2)
+endif()
+
+if(MINGW)
+ # needed for nanosleep() in mingw
+ target_link_libraries(regress_dev winpthread)
+endif()
diff --git a/regress/assert.c b/regress/assert.c
new file mode 100644
index 0000000..ad31903
--- /dev/null
+++ b/regress/assert.c
@@ -0,0 +1,685 @@
+/*
+ * Copyright (c) 2018-2023 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+#include
+#include
+#include
+
+static int fake_dev_handle;
+
+static const unsigned char es256_pk[64] = {
+ 0x34, 0xeb, 0x99, 0x77, 0x02, 0x9c, 0x36, 0x38,
+ 0xbb, 0xc2, 0xae, 0xa0, 0xa0, 0x18, 0xc6, 0x64,
+ 0xfc, 0xe8, 0x49, 0x92, 0xd7, 0x74, 0x9e, 0x0c,
+ 0x46, 0x8c, 0x9d, 0xa6, 0xdf, 0x46, 0xf7, 0x84,
+ 0x60, 0x1e, 0x0f, 0x8b, 0x23, 0x85, 0x4a, 0x9a,
+ 0xec, 0xc1, 0x08, 0x9f, 0x30, 0xd0, 0x0d, 0xd7,
+ 0x76, 0x7b, 0x55, 0x48, 0x91, 0x7c, 0x4f, 0x0f,
+ 0x64, 0x1a, 0x1d, 0xf8, 0xbe, 0x14, 0x90, 0x8a,
+};
+
+static const unsigned char rs256_pk[259] = {
+ 0x9e, 0x54, 0x78, 0xb2, 0x51, 0xbe, 0x19, 0x7c,
+ 0xcb, 0x1a, 0x9a, 0xc3, 0x49, 0x2a, 0x2f, 0xfd,
+ 0x99, 0x64, 0x76, 0xc6, 0xdb, 0xca, 0x38, 0x3f,
+ 0xb0, 0x6a, 0xc9, 0xc0, 0x07, 0x9f, 0x5c, 0x4d,
+ 0xfc, 0xd1, 0x01, 0x7f, 0x69, 0x65, 0xab, 0x9c,
+ 0x2a, 0xc2, 0x95, 0xd9, 0x44, 0xf3, 0xea, 0x94,
+ 0x6b, 0x25, 0x66, 0x54, 0x81, 0xee, 0x24, 0x1d,
+ 0xe1, 0x7d, 0x7f, 0xbe, 0xea, 0x76, 0x90, 0x5c,
+ 0xbf, 0x59, 0x22, 0xd3, 0xa0, 0x68, 0x1a, 0x65,
+ 0x8b, 0x2f, 0xb6, 0xa8, 0x30, 0x2d, 0x26, 0x81,
+ 0xfa, 0x9e, 0x59, 0xec, 0x2f, 0xee, 0x59, 0x39,
+ 0xe2, 0x79, 0x19, 0x54, 0x54, 0xdf, 0x24, 0x83,
+ 0xee, 0x61, 0x5a, 0x66, 0x24, 0x2b, 0x7b, 0xfb,
+ 0x82, 0x66, 0xe4, 0x85, 0x18, 0x20, 0x76, 0xe5,
+ 0x4a, 0xb6, 0xcb, 0xec, 0x43, 0xbe, 0xfd, 0xb0,
+ 0x8f, 0xfd, 0x2f, 0x69, 0xda, 0x06, 0x9c, 0x09,
+ 0x68, 0x7a, 0x94, 0x6c, 0xb7, 0x51, 0x6d, 0x4c,
+ 0xf7, 0x13, 0xe8, 0xd5, 0x22, 0x6b, 0x1e, 0xba,
+ 0xb9, 0x85, 0xe8, 0x5f, 0xa1, 0x66, 0xe3, 0x20,
+ 0x75, 0x30, 0x11, 0xb5, 0xa3, 0xc3, 0xb0, 0x72,
+ 0x08, 0xff, 0xa3, 0xbb, 0xf1, 0x32, 0x0b, 0x06,
+ 0xc4, 0x12, 0xa3, 0x49, 0x30, 0x19, 0xb9, 0xfe,
+ 0x69, 0x0c, 0xd6, 0xe1, 0x58, 0x36, 0xe6, 0x41,
+ 0x22, 0x41, 0xbf, 0x96, 0x50, 0x35, 0x56, 0x0d,
+ 0x92, 0x8c, 0x34, 0xea, 0x28, 0x91, 0x88, 0x9e,
+ 0x8a, 0xaa, 0x36, 0xd0, 0x0f, 0xbe, 0x16, 0xde,
+ 0x9d, 0x5f, 0x7b, 0xda, 0x52, 0xf7, 0xf1, 0xb6,
+ 0x28, 0x10, 0x05, 0x8f, 0xb9, 0x19, 0x7a, 0xcf,
+ 0x18, 0x9b, 0x40, 0xcd, 0xff, 0x78, 0xea, 0x61,
+ 0x24, 0x3b, 0x80, 0x68, 0x04, 0x9b, 0x40, 0x07,
+ 0x98, 0xd4, 0x94, 0xd1, 0x18, 0x44, 0xa5, 0xed,
+ 0xee, 0x18, 0xc2, 0x25, 0x52, 0x66, 0x42, 0xdf,
+ 0x01, 0x00, 0x01,
+};
+
+static const unsigned char cdh[32] = {
+ 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
+ 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
+ 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52,
+ 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76,
+};
+
+static const unsigned char authdata[39] = {
+ 0x58, 0x25, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e,
+ 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76,
+ 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86,
+ 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d,
+ 0x97, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03,
+};
+
+static const unsigned char sig[72] = {
+ 0x30, 0x46, 0x02, 0x21, 0x00, 0xf6, 0xd1, 0xa3,
+ 0xd5, 0x24, 0x2b, 0xde, 0xee, 0xa0, 0x90, 0x89,
+ 0xcd, 0xf8, 0x9e, 0xbd, 0x6b, 0x4d, 0x55, 0x79,
+ 0xe4, 0xc1, 0x42, 0x27, 0xb7, 0x9b, 0x9b, 0xa4,
+ 0x0a, 0xe2, 0x47, 0x64, 0x0e, 0x02, 0x21, 0x00,
+ 0xe5, 0xc9, 0xc2, 0x83, 0x47, 0x31, 0xc7, 0x26,
+ 0xe5, 0x25, 0xb2, 0xb4, 0x39, 0xa7, 0xfc, 0x3d,
+ 0x70, 0xbe, 0xe9, 0x81, 0x0d, 0x4a, 0x62, 0xa9,
+ 0xab, 0x4a, 0x91, 0xc0, 0x7d, 0x2d, 0x23, 0x1e,
+};
+
+static void *
+dummy_open(const char *path)
+{
+ (void)path;
+
+ return (&fake_dev_handle);
+}
+
+static void
+dummy_close(void *handle)
+{
+ assert(handle == &fake_dev_handle);
+}
+
+static int
+dummy_read(void *handle, unsigned char *buf, size_t len, int ms)
+{
+ (void)handle;
+ (void)buf;
+ (void)len;
+ (void)ms;
+
+ abort();
+ /* NOTREACHED */
+}
+
+static int
+dummy_write(void *handle, const unsigned char *buf, size_t len)
+{
+ (void)handle;
+ (void)buf;
+ (void)len;
+
+ abort();
+ /* NOTREACHED */
+}
+
+static fido_assert_t *
+alloc_assert(void)
+{
+ fido_assert_t *a;
+
+ a = fido_assert_new();
+ assert(a != NULL);
+
+ return (a);
+}
+
+static void
+free_assert(fido_assert_t *a)
+{
+ fido_assert_free(&a);
+ assert(a == NULL);
+}
+
+static fido_dev_t *
+alloc_dev(void)
+{
+ fido_dev_t *d;
+
+ d = fido_dev_new();
+ assert(d != NULL);
+
+ return (d);
+}
+
+static void
+free_dev(fido_dev_t *d)
+{
+ fido_dev_free(&d);
+ assert(d == NULL);
+}
+
+static es256_pk_t *
+alloc_es256_pk(void)
+{
+ es256_pk_t *pk;
+
+ pk = es256_pk_new();
+ assert(pk != NULL);
+
+ return (pk);
+}
+
+static void
+free_es256_pk(es256_pk_t *pk)
+{
+ es256_pk_free(&pk);
+ assert(pk == NULL);
+}
+
+static rs256_pk_t *
+alloc_rs256_pk(void)
+{
+ rs256_pk_t *pk;
+
+ pk = rs256_pk_new();
+ assert(pk != NULL);
+
+ return (pk);
+}
+
+static void
+free_rs256_pk(rs256_pk_t *pk)
+{
+ rs256_pk_free(&pk);
+ assert(pk == NULL);
+}
+
+static eddsa_pk_t *
+alloc_eddsa_pk(void)
+{
+ eddsa_pk_t *pk;
+
+ pk = eddsa_pk_new();
+ assert(pk != NULL);
+
+ return (pk);
+}
+
+static void
+free_eddsa_pk(eddsa_pk_t *pk)
+{
+ eddsa_pk_free(&pk);
+ assert(pk == NULL);
+}
+
+static void
+empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx)
+{
+ es256_pk_t *es256;
+ rs256_pk_t *rs256;
+ eddsa_pk_t *eddsa;
+
+ assert(fido_assert_flags(a, idx) == 0);
+ assert(fido_assert_authdata_len(a, idx) == 0);
+ assert(fido_assert_authdata_ptr(a, idx) == NULL);
+ assert(fido_assert_authdata_raw_len(a, idx) == 0);
+ assert(fido_assert_authdata_raw_ptr(a, idx) == NULL);
+ assert(fido_assert_clientdata_hash_len(a) == 0);
+ assert(fido_assert_clientdata_hash_ptr(a) == NULL);
+ assert(fido_assert_id_len(a, idx) == 0);
+ assert(fido_assert_id_ptr(a, idx) == NULL);
+ assert(fido_assert_rp_id(a) == NULL);
+ assert(fido_assert_sig_len(a, idx) == 0);
+ assert(fido_assert_sig_ptr(a, idx) == NULL);
+ assert(fido_assert_user_display_name(a, idx) == NULL);
+ assert(fido_assert_user_icon(a, idx) == NULL);
+ assert(fido_assert_user_id_len(a, idx) == 0);
+ assert(fido_assert_user_id_ptr(a, idx) == NULL);
+ assert(fido_assert_user_name(a, idx) == NULL);
+
+ es256 = alloc_es256_pk();
+ rs256 = alloc_rs256_pk();
+ eddsa = alloc_eddsa_pk();
+
+ fido_dev_force_u2f(d);
+ assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_ES256,
+ NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_ES256,
+ es256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, -1,
+ es256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_RS256,
+ rs256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_EDDSA,
+ eddsa) == FIDO_ERR_INVALID_ARGUMENT);
+
+ fido_dev_force_fido2(d);
+ assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_ES256,
+ NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_ES256,
+ es256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, -1,
+ es256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_RS256,
+ rs256) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_verify(a, idx, COSE_EDDSA,
+ eddsa) == FIDO_ERR_INVALID_ARGUMENT);
+
+ free_es256_pk(es256);
+ free_rs256_pk(rs256);
+ free_eddsa_pk(eddsa);
+}
+
+static void
+empty_assert_tests(void)
+{
+ fido_assert_t *a;
+ fido_dev_t *d;
+ fido_dev_io_t io_f;
+ size_t i;
+
+ memset(&io_f, 0, sizeof(io_f));
+
+ a = alloc_assert();
+ d = alloc_dev();
+
+ io_f.open = dummy_open;
+ io_f.close = dummy_close;
+ io_f.read = dummy_read;
+ io_f.write = dummy_write;
+
+ assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK);
+
+ empty_assert(d, a, 0);
+ assert(fido_assert_count(a) == 0);
+ assert(fido_assert_set_count(a, 4) == FIDO_OK);
+ assert(fido_assert_count(a) == 4);
+ for (i = 0; i < 4; i++) {
+ empty_assert(d, a, i);
+ }
+ empty_assert(d, a, 10);
+ free_assert(a);
+ free_dev(d);
+}
+
+static void
+valid_assert(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *es256;
+ rs256_pk_t *rs256;
+ eddsa_pk_t *eddsa;
+
+ a = alloc_assert();
+ es256 = alloc_es256_pk();
+ rs256 = alloc_rs256_pk();
+ eddsa = alloc_eddsa_pk();
+ assert(es256_pk_from_ptr(es256, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256, es256) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_RS256, rs256) == FIDO_ERR_INVALID_SIG);
+ assert(fido_assert_verify(a, 0, COSE_EDDSA, eddsa) == FIDO_ERR_INVALID_SIG);
+ free_assert(a);
+ free_es256_pk(es256);
+ free_rs256_pk(rs256);
+ free_eddsa_pk(eddsa);
+}
+
+static void
+no_cdh(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_ARGUMENT);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+static void
+no_rp(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_ARGUMENT);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+static void
+no_authdata(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_ARGUMENT);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+static void
+no_sig(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_ARGUMENT);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+static void
+junk_cdh(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(cdh));
+ assert(junk != NULL);
+ memcpy(junk, cdh, sizeof(cdh));
+ junk[0] = (unsigned char)~junk[0];
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, junk, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG);
+ free_assert(a);
+ free_es256_pk(pk);
+ free(junk);
+}
+
+static void
+junk_rp(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "potato") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_PARAM);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+static void
+junk_authdata(void)
+{
+ fido_assert_t *a;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(authdata));
+ assert(junk != NULL);
+ memcpy(junk, authdata, sizeof(authdata));
+ junk[0] = (unsigned char)~junk[0];
+
+ a = alloc_assert();
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, junk,
+ sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_assert_authdata_ptr(a, 0) == NULL);
+ assert(fido_assert_authdata_len(a, 0) == 0);
+ assert(fido_assert_authdata_raw_ptr(a, 0) == NULL);
+ assert(fido_assert_authdata_raw_len(a, 0) == 0);
+ free_assert(a);
+ free(junk);
+}
+
+static void
+junk_sig(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(sig));
+ assert(junk != NULL);
+ memcpy(junk, sig, sizeof(sig));
+ junk[0] = (unsigned char)~junk[0];
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, junk, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG);
+ free_assert(a);
+ free_es256_pk(pk);
+ free(junk);
+}
+
+static void
+wrong_options(void)
+{
+ fido_assert_t *a;
+ es256_pk_t *pk;
+
+ a = alloc_assert();
+ pk = alloc_es256_pk();
+ assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_assert_set_rp(a, "localhost") == FIDO_OK);
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_set_up(a, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_PARAM);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256,
+ pk) == FIDO_ERR_INVALID_PARAM);
+ assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK);
+ free_assert(a);
+ free_es256_pk(pk);
+}
+
+/* cbor_serialize_alloc misuse */
+static void
+bad_cbor_serialize(void)
+{
+ fido_assert_t *a;
+
+ a = alloc_assert();
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert(fido_assert_authdata_len(a, 0) == sizeof(authdata));
+ free_assert(a);
+}
+
+/* rs256 <-> EVP_PKEY transformations */
+static void
+rs256_PKEY(void)
+{
+ rs256_pk_t *pk1, *pk2;
+ EVP_PKEY *pkey;
+
+ pk1 = alloc_rs256_pk();
+ pk2 = alloc_rs256_pk();
+
+ assert(rs256_pk_from_ptr(pk1, rs256_pk, sizeof(rs256_pk)) == FIDO_OK);
+ assert((pkey = rs256_pk_to_EVP_PKEY(pk1)) != NULL);
+ assert(rs256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK);
+ assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0);
+
+ free_rs256_pk(pk1);
+ free_rs256_pk(pk2);
+ EVP_PKEY_free(pkey);
+}
+
+/* es256 <-> EVP_PKEY transformations */
+static void
+es256_PKEY(void)
+{
+ es256_pk_t *pk1, *pk2;
+ EVP_PKEY *pkey;
+
+ pk1 = alloc_es256_pk();
+ pk2 = alloc_es256_pk();
+
+ assert(es256_pk_from_ptr(pk1, es256_pk, sizeof(es256_pk)) == FIDO_OK);
+ assert((pkey = es256_pk_to_EVP_PKEY(pk1)) != NULL);
+ assert(es256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK);
+ assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0);
+
+ free_es256_pk(pk1);
+ free_es256_pk(pk2);
+ EVP_PKEY_free(pkey);
+}
+
+static void
+raw_authdata(void)
+{
+ fido_assert_t *a;
+ cbor_item_t *item;
+ struct cbor_load_result cbor_result;
+ const unsigned char *ptr;
+ unsigned char *cbor;
+ size_t len;
+ size_t cbor_len;
+ size_t alloclen;
+
+ a = alloc_assert();
+ assert(fido_assert_set_count(a, 1) == FIDO_OK);
+ assert(fido_assert_set_authdata(a, 0, authdata,
+ sizeof(authdata)) == FIDO_OK);
+ assert((ptr = fido_assert_authdata_ptr(a, 0)) != NULL);
+ assert((len = fido_assert_authdata_len(a, 0)) != 0);
+ assert((item = cbor_load(ptr, len, &cbor_result)) != NULL);
+ assert(cbor_result.read == len);
+ assert(cbor_isa_bytestring(item));
+ assert((ptr = fido_assert_authdata_raw_ptr(a, 0)) != NULL);
+ assert((len = fido_assert_authdata_raw_len(a, 0)) != 0);
+ assert(cbor_bytestring_length(item) == len);
+ assert(memcmp(ptr, cbor_bytestring_handle(item), len) == 0);
+ assert((len = fido_assert_authdata_len(a, 0)) != 0);
+ assert((cbor_len = cbor_serialize_alloc(item, &cbor, &alloclen)) == len);
+ assert((ptr = cbor_bytestring_handle(item)) != NULL);
+ assert((len = cbor_bytestring_length(item)) != 0);
+ assert(fido_assert_set_authdata_raw(a, 0, ptr, len) == FIDO_OK);
+ assert((ptr = fido_assert_authdata_ptr(a, 0)) != NULL);
+ assert((len = fido_assert_authdata_len(a, 0)) != 0);
+ assert(len == cbor_len);
+ assert(memcmp(cbor, ptr, len) == 0);
+ assert(cbor_len == sizeof(authdata));
+ assert(memcmp(cbor, authdata, cbor_len) == 0);
+ cbor_decref(&item);
+ free(cbor);
+ free_assert(a);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ empty_assert_tests();
+ valid_assert();
+ no_cdh();
+ no_rp();
+ no_authdata();
+ no_sig();
+ junk_cdh();
+ junk_rp();
+ junk_authdata();
+ junk_sig();
+ wrong_options();
+ bad_cbor_serialize();
+ rs256_PKEY();
+ es256_PKEY();
+ raw_authdata();
+
+ exit(0);
+}
diff --git a/regress/compress.c b/regress/compress.c
new file mode 100644
index 0000000..7afc8bb
--- /dev/null
+++ b/regress/compress.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+
+/*
+ * zlib compressed data (RFC1950); see https://www.ietf.org/rfc/rfc6713.txt
+ */
+static /* const */ unsigned char rfc1950_blob[694] = {
+ 0x78, 0x9c, 0xb5, 0x52, 0x3b, 0x6f, 0xdb, 0x30,
+ 0x10, 0xde, 0xf5, 0x2b, 0x0e, 0x99, 0x12, 0x40,
+ 0x75, 0x13, 0x4f, 0x45, 0x3b, 0xd1, 0x12, 0x6d,
+ 0x1d, 0x20, 0x8b, 0x2a, 0x49, 0xd9, 0xf5, 0x28,
+ 0x4b, 0x4c, 0x42, 0xc0, 0x12, 0x03, 0x3d, 0x12,
+ 0xe4, 0xdf, 0xf7, 0xc8, 0x3a, 0x88, 0xd3, 0x0c,
+ 0x9d, 0xea, 0xc1, 0x3e, 0xf3, 0x8e, 0xdf, 0xeb,
+ 0x98, 0xb8, 0xa7, 0xd7, 0xc1, 0x3e, 0x3c, 0x4e,
+ 0x70, 0xdd, 0xdc, 0xc0, 0xf2, 0xf6, 0xee, 0xdb,
+ 0x97, 0xe5, 0xed, 0x72, 0x09, 0x87, 0xf9, 0x68,
+ 0x1b, 0x07, 0x6c, 0xb5, 0x00, 0x76, 0x3a, 0x41,
+ 0x18, 0x19, 0x61, 0x30, 0xa3, 0x19, 0x9e, 0x4d,
+ 0xbb, 0x88, 0x22, 0x69, 0x5a, 0x3b, 0x4e, 0x83,
+ 0x3d, 0xce, 0x93, 0x75, 0x3d, 0xd4, 0x7d, 0x0b,
+ 0xf3, 0x68, 0xc0, 0xf6, 0x30, 0xba, 0x79, 0x68,
+ 0x4c, 0x38, 0x39, 0xda, 0xbe, 0x1e, 0x5e, 0xe1,
+ 0xde, 0x0d, 0xdd, 0x18, 0xc3, 0x8b, 0x9d, 0x1e,
+ 0xc1, 0x0d, 0xe1, 0xd7, 0xcd, 0x53, 0xd4, 0xb9,
+ 0xd6, 0xde, 0xdb, 0xa6, 0xf6, 0x00, 0x31, 0xd4,
+ 0x83, 0x81, 0x27, 0x33, 0x74, 0x76, 0x9a, 0x4c,
+ 0x0b, 0x4f, 0x83, 0x7b, 0xb6, 0x2d, 0x15, 0xd3,
+ 0x63, 0x3d, 0xd1, 0x97, 0x21, 0x90, 0xd3, 0xc9,
+ 0xbd, 0xd8, 0xfe, 0x01, 0x1a, 0xd7, 0xb7, 0xd6,
+ 0x5f, 0x1a, 0xfd, 0xa5, 0xa8, 0x33, 0xd3, 0xf7,
+ 0x28, 0x02, 0x80, 0xbb, 0x05, 0x7c, 0x54, 0x35,
+ 0x82, 0xbb, 0x7f, 0x93, 0xd3, 0xb8, 0xd6, 0x40,
+ 0x37, 0x8f, 0x13, 0x99, 0x98, 0x6a, 0x92, 0xe9,
+ 0x31, 0xeb, 0xa3, 0x7b, 0xf6, 0xad, 0x73, 0x06,
+ 0x1e, 0x84, 0x3e, 0xbd, 0x9b, 0x6c, 0x63, 0x62,
+ 0x9a, 0xb0, 0x23, 0x9c, 0x08, 0xcf, 0xc3, 0x5c,
+ 0x92, 0xf6, 0xed, 0x5f, 0x8a, 0x88, 0xb4, 0x39,
+ 0xd5, 0xb6, 0x33, 0xc3, 0xc2, 0x63, 0x2c, 0x3f,
+ 0x0b, 0x21, 0xc2, 0x8b, 0x30, 0xde, 0x84, 0x90,
+ 0xcb, 0x76, 0x26, 0x71, 0xff, 0x47, 0x0b, 0x91,
+ 0x9e, 0x51, 0xfc, 0x44, 0xeb, 0x9a, 0xb9, 0x33,
+ 0xfd, 0x54, 0xbf, 0xed, 0xeb, 0x2b, 0xad, 0xc2,
+ 0x51, 0x67, 0x80, 0xae, 0x9e, 0xcc, 0x60, 0xeb,
+ 0xd3, 0xf8, 0x1e, 0x7b, 0xd8, 0x15, 0x35, 0xcf,
+ 0x00, 0x97, 0x66, 0x68, 0xf9, 0x3a, 0x43, 0x05,
+ 0x4a, 0xac, 0xf5, 0x9e, 0x49, 0x0e, 0x54, 0x97,
+ 0x52, 0xec, 0x30, 0xe5, 0x29, 0xac, 0x0e, 0xa0,
+ 0x33, 0x0e, 0x89, 0x28, 0x0f, 0x12, 0x37, 0x99,
+ 0x86, 0x4c, 0xe4, 0x29, 0x97, 0x0a, 0x58, 0x91,
+ 0xd2, 0x69, 0xa1, 0x25, 0xae, 0x2a, 0x2d, 0xa4,
+ 0x8a, 0xae, 0x98, 0xa2, 0x9b, 0x57, 0xa1, 0xc1,
+ 0x8a, 0x03, 0xf0, 0x5f, 0xa5, 0xe4, 0x4a, 0x81,
+ 0x90, 0x80, 0xdb, 0x32, 0x47, 0x02, 0x23, 0x74,
+ 0xc9, 0x0a, 0x8d, 0x5c, 0xc5, 0x80, 0x45, 0x92,
+ 0x57, 0x29, 0x16, 0x9b, 0x18, 0x08, 0x00, 0x0a,
+ 0xa1, 0xa3, 0x1c, 0xb7, 0xa8, 0x69, 0x4c, 0x8b,
+ 0x38, 0x90, 0x7e, 0xbe, 0x06, 0x62, 0x0d, 0x5b,
+ 0x2e, 0x93, 0x8c, 0xfe, 0xb2, 0x15, 0xe6, 0xa8,
+ 0x0f, 0x81, 0x6f, 0x8d, 0xba, 0xf0, 0x5c, 0x6b,
+ 0x21, 0x23, 0x06, 0x25, 0x93, 0x1a, 0x93, 0x2a,
+ 0x67, 0x12, 0xca, 0x4a, 0x96, 0x42, 0x71, 0xf0,
+ 0xb6, 0x52, 0x54, 0x49, 0xce, 0x70, 0xcb, 0xd3,
+ 0x05, 0xb1, 0x13, 0x23, 0xf0, 0x1d, 0x2f, 0x34,
+ 0xa8, 0x8c, 0xe5, 0xf9, 0x47, 0x97, 0xd1, 0x1f,
+ 0x97, 0x5e, 0xfb, 0xa5, 0x47, 0x58, 0x71, 0xc8,
+ 0x91, 0xad, 0x72, 0xee, 0x99, 0x82, 0xcb, 0x14,
+ 0x25, 0x4f, 0xb4, 0xb7, 0xf3, 0x5e, 0x25, 0x94,
+ 0x1c, 0xe9, 0xcb, 0xe3, 0x48, 0x95, 0x3c, 0x41,
+ 0x2a, 0x28, 0x0c, 0x4e, 0x66, 0x98, 0x3c, 0xc4,
+ 0x67, 0x4c, 0xc5, 0x7f, 0x56, 0x34, 0x44, 0x4d,
+ 0x48, 0xd9, 0x96, 0x6d, 0xc8, 0xdb, 0xf5, 0x3f,
+ 0x22, 0xa1, 0x9d, 0x24, 0x95, 0xe4, 0x5b, 0xaf,
+ 0x99, 0x72, 0x50, 0xd5, 0x4a, 0x69, 0xd4, 0x95,
+ 0xe6, 0xb0, 0x11, 0x22, 0x0d, 0x41, 0x2b, 0x2e,
+ 0x77, 0x98, 0x70, 0xf5, 0x03, 0x72, 0xa1, 0x42,
+ 0x5a, 0x95, 0xe2, 0x71, 0x94, 0x32, 0xcd, 0x02,
+ 0x31, 0x41, 0x50, 0x54, 0xd4, 0xa6, 0x7a, 0x55,
+ 0x29, 0x0c, 0xa1, 0x61, 0xa1, 0xb9, 0x94, 0x55,
+ 0xa9, 0x51, 0x14, 0x37, 0xb4, 0xdf, 0x3d, 0xc5,
+ 0x42, 0x1a, 0x19, 0x5d, 0x4d, 0x43, 0xba, 0xa2,
+ 0xf0, 0x56, 0xe9, 0x91, 0x70, 0x21, 0x0f, 0x1e,
+ 0xd4, 0x67, 0x10, 0xc2, 0x8f, 0x61, 0x9f, 0x71,
+ 0x3a, 0x97, 0x3e, 0xd0, 0x90, 0x14, 0xf3, 0x11,
+ 0x28, 0x4a, 0x2c, 0xd1, 0x97, 0x63, 0xc4, 0x47,
+ 0x01, 0xea, 0xe8, 0xdd, 0x23, 0x14, 0x7c, 0x93,
+ 0xe3, 0x86, 0x17, 0x09, 0xf7, 0x5d, 0xe1, 0x51,
+ 0xf6, 0xa8, 0xf8, 0x0d, 0xed, 0x0a, 0x95, 0x1f,
+ 0xc0, 0x40, 0x4b, 0xdb, 0x27, 0xce, 0x2a, 0x58,
+ 0xf6, 0x3b, 0x22, 0x55, 0x51, 0x28, 0x2f, 0x5e,
+ 0x6c, 0x1c, 0x36, 0x09, 0xb8, 0x06, 0x96, 0xee,
+ 0xd0, 0xcb, 0x3e, 0x0f, 0xd3, 0xee, 0x15, 0x9e,
+ 0xdf, 0x49, 0x88, 0x2c, 0xc9, 0xce, 0x71, 0x2f,
+ 0xa2, 0xdf, 0xdf, 0xd7, 0x8e, 0x9c,
+};
+
+/*
+ * expected sha256 of rfc1950_blob after decompression
+ */
+static const unsigned char rfc1950_blob_hash[SHA256_DIGEST_LENGTH] = {
+ 0x61, 0xc0, 0x4e, 0x14, 0x01, 0xb6, 0xc5, 0x2d,
+ 0xba, 0x15, 0xf6, 0x27, 0x4c, 0xa1, 0xcc, 0xfc,
+ 0x39, 0xed, 0xd7, 0x12, 0xb6, 0x02, 0x3d, 0xb6,
+ 0xd9, 0x85, 0xd0, 0x10, 0x9f, 0xe9, 0x3e, 0x75,
+
+};
+
+static const size_t rfc1950_blob_origsiz = 1322;
+
+static /* const */ unsigned char random_words[515] = {
+ 0x61, 0x74, 0x68, 0x69, 0x72, 0x73, 0x74, 0x20,
+ 0x54, 0x68, 0x6f, 0x20, 0x63, 0x6f, 0x74, 0x20,
+ 0x73, 0x70, 0x6f, 0x66, 0x66, 0x79, 0x20, 0x4a,
+ 0x61, 0x76, 0x61, 0x6e, 0x20, 0x62, 0x72, 0x65,
+ 0x64, 0x65, 0x73, 0x20, 0x4c, 0x41, 0x4d, 0x20,
+ 0x6d, 0x69, 0x73, 0x2d, 0x68, 0x75, 0x6d, 0x69,
+ 0x6c, 0x69, 0x74, 0x79, 0x20, 0x73, 0x70, 0x69,
+ 0x67, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x76, 0x6f,
+ 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x6c, 0x79, 0x20,
+ 0x49, 0x6f, 0x64, 0x61, 0x6d, 0x6f, 0x65, 0x62,
+ 0x61, 0x20, 0x68, 0x79, 0x70, 0x6f, 0x68, 0x79,
+ 0x64, 0x72, 0x6f, 0x63, 0x68, 0x6c, 0x6f, 0x72,
+ 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d,
+ 0x65, 0x74, 0x74, 0x65, 0x20, 0x61, 0x63, 0x72,
+ 0x69, 0x64, 0x69, 0x6e, 0x65, 0x20, 0x68, 0x6f,
+ 0x77, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x79, 0x67,
+ 0x61, 0x65, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e,
+ 0x63, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x73,
+ 0x74, 0x20, 0x74, 0x65, 0x74, 0x72, 0x61, 0x70,
+ 0x6c, 0x6f, 0x69, 0x64, 0x20, 0x61, 0x75, 0x78,
+ 0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72,
+ 0x69, 0x70, 0x65, 0x2d, 0x67, 0x72, 0x6f, 0x77,
+ 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72,
+ 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x79, 0x63,
+ 0x6f, 0x63, 0x65, 0x63, 0x69, 0x64, 0x69, 0x75,
+ 0x6d, 0x20, 0x50, 0x65, 0x64, 0x65, 0x72, 0x73,
+ 0x6f, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x64, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x62, 0x6f, 0x75,
+ 0x6e, 0x64, 0x20, 0x4c, 0x65, 0x6e, 0x67, 0x6c,
+ 0x65, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x73, 0x62,
+ 0x79, 0x74, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20,
+ 0x6c, 0x65, 0x63, 0x79, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x64, 0x72,
+ 0x69, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61,
+ 0x6c, 0x6c, 0x6f, 0x6b, 0x75, 0x72, 0x74, 0x69,
+ 0x63, 0x20, 0x75, 0x6e, 0x64, 0x69, 0x76, 0x69,
+ 0x73, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x20, 0x70,
+ 0x73, 0x79, 0x63, 0x68, 0x6f, 0x6b, 0x79, 0x6d,
+ 0x65, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x73,
+ 0x74, 0x61, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65,
+ 0x6e, 0x65, 0x73, 0x73, 0x20, 0x63, 0x75, 0x6c,
+ 0x74, 0x69, 0x73, 0x68, 0x20, 0x52, 0x65, 0x69,
+ 0x63, 0x68, 0x73, 0x74, 0x61, 0x67, 0x20, 0x75,
+ 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x72, 0x69, 0x6e,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x6c, 0x6f, 0x67,
+ 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72,
+ 0x20, 0x4c, 0x61, 0x69, 0x74, 0x68, 0x20, 0x74,
+ 0x77, 0x6f, 0x2d, 0x66, 0x61, 0x63, 0x65, 0x20,
+ 0x4d, 0x75, 0x70, 0x68, 0x72, 0x69, 0x64, 0x20,
+ 0x70, 0x72, 0x6f, 0x72, 0x65, 0x63, 0x69, 0x70,
+ 0x72, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x6c, 0x69, 0x62, 0x72, 0x65, 0x74, 0x74,
+ 0x69, 0x73, 0x74, 0x20, 0x49, 0x62, 0x69, 0x62,
+ 0x69, 0x6f, 0x20, 0x72, 0x65, 0x67, 0x72, 0x65,
+ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x63,
+ 0x6f, 0x6e, 0x64, 0x69, 0x67, 0x6e, 0x6e, 0x65,
+ 0x73, 0x73, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65,
+ 0x2d, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65,
+ 0x64, 0x20, 0x73, 0x79, 0x6e, 0x61, 0x70, 0x74,
+ 0x65, 0x6e, 0x65, 0x20, 0x68, 0x6f, 0x6c, 0x6f,
+ 0x6d, 0x6f, 0x72, 0x70, 0x68, 0x20, 0x6d, 0x6f,
+ 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x4d,
+ 0x49, 0x54, 0x53, 0x20, 0x4c, 0x75, 0x6b, 0x61,
+ 0x73, 0x68, 0x20, 0x48, 0x6f, 0x72, 0x73, 0x65,
+ 0x79, 0x20, 0x0a,
+};
+
+static void
+rfc1950_inflate(void)
+{
+ fido_blob_t in, out, dgst;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ memset(&dgst, 0, sizeof(dgst));
+ in.ptr = rfc1950_blob;
+ in.len = sizeof(rfc1950_blob);
+
+ assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK);
+ assert(out.len == rfc1950_blob_origsiz);
+ assert(fido_sha256(&dgst, out.ptr, out.len) == 0);
+ assert(dgst.len == sizeof(rfc1950_blob_hash));
+ assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0);
+
+ free(out.ptr);
+ free(dgst.ptr);
+}
+
+static void
+rfc1951_inflate(void)
+{
+ fido_blob_t in, out, dgst;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ memset(&dgst, 0, sizeof(dgst));
+ in.ptr = rfc1950_blob + 2; /* trim header */
+ in.len = sizeof(rfc1950_blob) - 6; /* trim header (2), checksum (4) */
+
+ assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK);
+ assert(out.len == rfc1950_blob_origsiz);
+ assert(fido_sha256(&dgst, out.ptr, out.len) == 0);
+ assert(dgst.len == sizeof(rfc1950_blob_hash));
+ assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0);
+
+ free(out.ptr);
+ free(dgst.ptr);
+}
+
+static void
+rfc1951_reinflate(void)
+{
+ fido_blob_t in, out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.ptr = random_words;
+ in.len = sizeof(random_words);
+
+ assert(fido_compress(&out, &in) == FIDO_OK);
+
+ in.ptr = out.ptr;
+ in.len = out.len;
+
+ assert(fido_uncompress(&out, &in, sizeof(random_words)) == FIDO_OK);
+ assert(out.len == sizeof(random_words));
+ assert(memcmp(out.ptr, random_words, out.len) == 0);
+
+ free(in.ptr);
+ free(out.ptr);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ rfc1950_inflate();
+ rfc1951_inflate();
+ rfc1951_reinflate();
+
+ exit(0);
+}
diff --git a/regress/cred.c b/regress/cred.c
new file mode 100644
index 0000000..00c555e
--- /dev/null
+++ b/regress/cred.c
@@ -0,0 +1,2662 @@
+/*
+ * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+
+static int fake_dev_handle;
+
+static const unsigned char cdh[32] = {
+ 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
+ 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26,
+ 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31,
+ 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b,
+};
+
+static const unsigned char authdata[198] = {
+ 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e,
+ 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76,
+ 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86,
+ 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d,
+ 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80,
+ 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00,
+ 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde,
+ 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d,
+ 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e,
+ 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda,
+ 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83,
+ 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76,
+ 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6,
+ 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f,
+ 0x25, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
+ 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56,
+ 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78,
+ 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9,
+ 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5,
+ 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f,
+ 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3,
+ 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31,
+ 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d,
+ 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
+};
+
+static const unsigned char authdata_dupkeys[200] = {
+ 0x58, 0xc6, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e,
+ 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76,
+ 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86,
+ 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d,
+ 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80,
+ 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00,
+ 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde,
+ 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d,
+ 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e,
+ 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda,
+ 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83,
+ 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76,
+ 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6,
+ 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f,
+ 0x25, 0xa6, 0x01, 0x02, 0x01, 0x02, 0x03, 0x26,
+ 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27,
+ 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55,
+ 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd,
+ 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22,
+ 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20,
+ 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f,
+ 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6,
+ 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1,
+ 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
+};
+
+static const unsigned char authdata_unsorted_keys[198] = {
+ 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e,
+ 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76,
+ 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86,
+ 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d,
+ 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80,
+ 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00,
+ 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde,
+ 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d,
+ 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e,
+ 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda,
+ 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83,
+ 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76,
+ 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6,
+ 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f,
+ 0x25, 0xa5, 0x03, 0x26, 0x01, 0x02, 0x20, 0x01,
+ 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56,
+ 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78,
+ 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9,
+ 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5,
+ 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f,
+ 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3,
+ 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31,
+ 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d,
+ 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
+};
+
+const unsigned char authdata_tpm_rs256[362] = {
+ 0x59, 0x01, 0x67, 0x49, 0x96, 0x0d, 0xe5, 0x88,
+ 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64,
+ 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2,
+ 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83,
+ 0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81,
+ 0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96,
+ 0x00, 0x20, 0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29,
+ 0xe5, 0x3e, 0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a,
+ 0x4f, 0x03, 0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a,
+ 0x6b, 0x02, 0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e,
+ 0x38, 0x1a, 0xa4, 0x01, 0x03, 0x03, 0x39, 0x01,
+ 0x00, 0x20, 0x59, 0x01, 0x00, 0xc5, 0xb6, 0x9c,
+ 0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99, 0x7d,
+ 0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90, 0x05,
+ 0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1, 0x43,
+ 0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27, 0x91,
+ 0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80, 0x1b,
+ 0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34, 0xd6,
+ 0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee, 0x70,
+ 0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b, 0x4c,
+ 0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a, 0x46,
+ 0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3, 0x07,
+ 0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a, 0xd2,
+ 0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b, 0xc9,
+ 0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a, 0x3a,
+ 0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b, 0xae,
+ 0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63, 0xac,
+ 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b, 0x9f,
+ 0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d, 0xcc,
+ 0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe, 0x8b,
+ 0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67, 0x40,
+ 0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8, 0x14,
+ 0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69, 0xc6,
+ 0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee, 0x1f,
+ 0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f, 0x47,
+ 0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8, 0x13,
+ 0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84, 0x93,
+ 0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d, 0xc7,
+ 0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca, 0xd6,
+ 0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce, 0x92,
+ 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3, 0xed,
+ 0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e, 0x1b,
+ 0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5, 0x2c,
+ 0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x21, 0x43, 0x01,
+ 0x00, 0x01
+};
+
+static const unsigned char authdata_tpm_es256[166] = {
+ 0x58, 0xa4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e,
+ 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76,
+ 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86,
+ 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d,
+ 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81, 0xb6,
+ 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96, 0x00,
+ 0x20, 0xa8, 0xdf, 0x03, 0xf7, 0xbf, 0x39, 0x51,
+ 0x94, 0x95, 0x8f, 0xa4, 0x84, 0x97, 0x30, 0xbc,
+ 0x3c, 0x7e, 0x1c, 0x99, 0x91, 0x4d, 0xae, 0x6d,
+ 0xfb, 0xdf, 0x53, 0xb5, 0xb6, 0x1f, 0x3a, 0x4e,
+ 0x6a, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
+ 0x21, 0x58, 0x20, 0xfb, 0xd6, 0xba, 0x74, 0xe6,
+ 0x6e, 0x5c, 0x87, 0xef, 0x89, 0xa2, 0xe8, 0x3d,
+ 0x0b, 0xe9, 0x69, 0x2c, 0x07, 0x07, 0x7a, 0x8a,
+ 0x1e, 0xce, 0x12, 0xea, 0x3b, 0xb3, 0xf1, 0xf3,
+ 0xd9, 0xc3, 0xe6, 0x22, 0x58, 0x20, 0x3c, 0x68,
+ 0x51, 0x94, 0x54, 0x8d, 0xeb, 0x9f, 0xb2, 0x2c,
+ 0x66, 0x75, 0xb6, 0xb7, 0x55, 0x22, 0x0d, 0x87,
+ 0x59, 0xc4, 0x39, 0x91, 0x62, 0x17, 0xc2, 0xc3,
+ 0x53, 0xa5, 0x26, 0x97, 0x4f, 0x2d
+};
+
+static const unsigned char x509[742] = {
+ 0x30, 0x82, 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02,
+ 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+ 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75,
+ 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46,
+ 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41,
+ 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35,
+ 0x31, 0x35, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34,
+ 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31,
+ 0x34, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a,
+ 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62,
+ 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x45, 0x30,
+ 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
+ 0x00, 0x04, 0xdb, 0x0a, 0xdb, 0xf5, 0x21, 0xc7,
+ 0x5c, 0xce, 0x63, 0xdc, 0xa6, 0xe1, 0xe8, 0x25,
+ 0x06, 0x0d, 0x94, 0xe6, 0x27, 0x54, 0x19, 0x4f,
+ 0x9d, 0x24, 0xaf, 0x26, 0x1a, 0xbe, 0xad, 0x99,
+ 0x44, 0x1f, 0x95, 0xa3, 0x71, 0x91, 0x0a, 0x3a,
+ 0x20, 0xe7, 0x3e, 0x91, 0x5e, 0x13, 0xe8, 0xbe,
+ 0x38, 0x05, 0x7a, 0xd5, 0x7a, 0xa3, 0x7e, 0x76,
+ 0x90, 0x8f, 0xaf, 0xe2, 0x8a, 0x94, 0xb6, 0x30,
+ 0xeb, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+ 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x95, 0x40,
+ 0x6b, 0x50, 0x61, 0x7d, 0xad, 0x84, 0xa3, 0xb4,
+ 0xeb, 0x88, 0x0f, 0xe3, 0x30, 0x0f, 0x2d, 0xa2,
+ 0x0a, 0x00, 0xd9, 0x25, 0x04, 0xee, 0x72, 0xfa,
+ 0x67, 0xdf, 0x58, 0x51, 0x0f, 0x0b, 0x47, 0x02,
+ 0x9c, 0x3e, 0x41, 0x29, 0x4a, 0x93, 0xac, 0x29,
+ 0x85, 0x89, 0x2d, 0xa4, 0x7a, 0x81, 0x32, 0x28,
+ 0x57, 0x71, 0x01, 0xef, 0xa8, 0x42, 0x88, 0x16,
+ 0x96, 0x37, 0x91, 0xd5, 0xdf, 0xe0, 0x8f, 0xc9,
+ 0x3c, 0x8d, 0xb0, 0xcd, 0x89, 0x70, 0x82, 0xec,
+ 0x79, 0xd3, 0xc6, 0x78, 0x73, 0x29, 0x32, 0xe5,
+ 0xab, 0x6c, 0xbd, 0x56, 0x9f, 0xd5, 0x45, 0x91,
+ 0xce, 0xc1, 0xdd, 0x8d, 0x64, 0xdc, 0xe9, 0x9c,
+ 0x1f, 0x5e, 0x3c, 0xd2, 0xaf, 0x51, 0xa5, 0x82,
+ 0x18, 0xaf, 0xe0, 0x37, 0xe7, 0x32, 0x9e, 0x76,
+ 0x05, 0x77, 0x02, 0x7b, 0xe6, 0x24, 0xa0, 0x31,
+ 0x56, 0x1b, 0xfd, 0x19, 0xc5, 0x71, 0xd3, 0xf0,
+ 0x9e, 0xc0, 0x73, 0x05, 0x4e, 0xbc, 0x85, 0xb8,
+ 0x53, 0x9e, 0xef, 0xc5, 0xbc, 0x9c, 0x56, 0xa3,
+ 0xba, 0xd9, 0x27, 0x6a, 0xbb, 0xa9, 0x7a, 0x40,
+ 0xd7, 0x47, 0x8b, 0x55, 0x72, 0x6b, 0xe3, 0xfe,
+ 0x28, 0x49, 0x71, 0x24, 0xf4, 0x8f, 0xf4, 0x20,
+ 0x81, 0xea, 0x38, 0xff, 0x7c, 0x0a, 0x4f, 0xdf,
+ 0x02, 0x82, 0x39, 0x81, 0x82, 0x3b, 0xca, 0x09,
+ 0xdd, 0xca, 0xaa, 0x0f, 0x27, 0xf5, 0xa4, 0x83,
+ 0x55, 0x6c, 0x9a, 0x39, 0x9b, 0x15, 0x3a, 0x16,
+ 0x63, 0xdc, 0x5b, 0xf9, 0xac, 0x5b, 0xbc, 0xf7,
+ 0x9f, 0xbe, 0x0f, 0x8a, 0xa2, 0x3c, 0x31, 0x13,
+ 0xa3, 0x32, 0x48, 0xca, 0x58, 0x87, 0xf8, 0x7b,
+ 0xa0, 0xa1, 0x0a, 0x6a, 0x60, 0x96, 0x93, 0x5f,
+ 0x5d, 0x26, 0x9e, 0x63, 0x1d, 0x09, 0xae, 0x9a,
+ 0x41, 0xe5, 0xbd, 0x08, 0x47, 0xfe, 0xe5, 0x09,
+ 0x9b, 0x20, 0xfd, 0x12, 0xe2, 0xe6, 0x40, 0x7f,
+ 0xba, 0x4a, 0x61, 0x33, 0x66, 0x0d, 0x0e, 0x73,
+ 0xdb, 0xb0, 0xd5, 0xa2, 0x9a, 0x9a, 0x17, 0x0d,
+ 0x34, 0x30, 0x85, 0x6a, 0x42, 0x46, 0x9e, 0xff,
+ 0x34, 0x8f, 0x5f, 0x87, 0x6c, 0x35, 0xe7, 0xa8,
+ 0x4d, 0x35, 0xeb, 0xc1, 0x41, 0xaa, 0x8a, 0xd2,
+ 0xda, 0x19, 0xaa, 0x79, 0xa2, 0x5f, 0x35, 0x2c,
+ 0xa0, 0xfd, 0x25, 0xd3, 0xf7, 0x9d, 0x25, 0x18,
+ 0x2d, 0xfa, 0xb4, 0xbc, 0xbb, 0x07, 0x34, 0x3c,
+ 0x8d, 0x81, 0xbd, 0xf4, 0xe9, 0x37, 0xdb, 0x39,
+ 0xe9, 0xd1, 0x45, 0x5b, 0x20, 0x41, 0x2f, 0x2d,
+ 0x27, 0x22, 0xdc, 0x92, 0x74, 0x8a, 0x92, 0xd5,
+ 0x83, 0xfd, 0x09, 0xfb, 0x13, 0x9b, 0xe3, 0x39,
+ 0x7a, 0x6b, 0x5c, 0xfa, 0xe6, 0x76, 0x9e, 0xe0,
+ 0xe4, 0xe3, 0xef, 0xad, 0xbc, 0xfd, 0x42, 0x45,
+ 0x9a, 0xd4, 0x94, 0xd1, 0x7e, 0x8d, 0xa7, 0xd8,
+ 0x05, 0xd5, 0xd3, 0x62, 0xcf, 0x15, 0xcf, 0x94,
+ 0x7d, 0x1f, 0x5b, 0x58, 0x20, 0x44, 0x20, 0x90,
+ 0x71, 0xbe, 0x66, 0xe9, 0x9a, 0xab, 0x74, 0x32,
+ 0x70, 0x53, 0x1d, 0x69, 0xed, 0x87, 0x66, 0xf4,
+ 0x09, 0x4f, 0xca, 0x25, 0x30, 0xc2, 0x63, 0x79,
+ 0x00, 0x3c, 0xb1, 0x9b, 0x39, 0x3f, 0x00, 0xe0,
+ 0xa8, 0x88, 0xef, 0x7a, 0x51, 0x5b, 0xe7, 0xbd,
+ 0x49, 0x64, 0xda, 0x41, 0x7b, 0x24, 0xc3, 0x71,
+ 0x22, 0xfd, 0xd1, 0xd1, 0x20, 0xb3, 0x3f, 0x97,
+ 0xd3, 0x97, 0xb2, 0xaa, 0x18, 0x1c, 0x9e, 0x03,
+ 0x77, 0x7b, 0x5b, 0x7e, 0xf9, 0xa3, 0xa0, 0xd6,
+ 0x20, 0x81, 0x2c, 0x38, 0x8f, 0x9d, 0x25, 0xde,
+ 0xe9, 0xc8, 0xf5, 0xdd, 0x6a, 0x47, 0x9c, 0x65,
+ 0x04, 0x5a, 0x56, 0xe6, 0xc2, 0xeb, 0xf2, 0x02,
+ 0x97, 0xe1, 0xb9, 0xd8, 0xe1, 0x24, 0x76, 0x9f,
+ 0x23, 0x62, 0x39, 0x03, 0x4b, 0xc8, 0xf7, 0x34,
+ 0x07, 0x49, 0xd6, 0xe7, 0x4d, 0x9a,
+};
+
+const unsigned char sig[70] = {
+ 0x30, 0x44, 0x02, 0x20, 0x54, 0x92, 0x28, 0x3b,
+ 0x83, 0x33, 0x47, 0x56, 0x68, 0x79, 0xb2, 0x0c,
+ 0x84, 0x80, 0xcc, 0x67, 0x27, 0x8b, 0xfa, 0x48,
+ 0x43, 0x0d, 0x3c, 0xb4, 0x02, 0x36, 0x87, 0x97,
+ 0x3e, 0xdf, 0x2f, 0x65, 0x02, 0x20, 0x1b, 0x56,
+ 0x17, 0x06, 0xe2, 0x26, 0x0f, 0x6a, 0xe9, 0xa9,
+ 0x70, 0x99, 0x62, 0xeb, 0x3a, 0x04, 0x1a, 0xc4,
+ 0xa7, 0x03, 0x28, 0x56, 0x7c, 0xed, 0x47, 0x08,
+ 0x68, 0x73, 0x6a, 0xb6, 0x89, 0x0d,
+};
+
+const unsigned char pubkey[64] = {
+ 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c,
+ 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c,
+ 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5,
+ 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6,
+ 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f,
+ 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6,
+ 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1,
+ 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
+};
+
+const unsigned char pubkey_tpm_rs256[259] = {
+ 0xc5, 0xb6, 0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2,
+ 0x5e, 0x99, 0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1,
+ 0x4a, 0x90, 0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6,
+ 0x6a, 0xd1, 0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f,
+ 0xd2, 0x27, 0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68,
+ 0xf8, 0x80, 0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11,
+ 0x86, 0x34, 0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79,
+ 0x84, 0xee, 0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4,
+ 0x43, 0x0b, 0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75,
+ 0x63, 0x8a, 0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71,
+ 0xd1, 0xb3, 0x07, 0x68, 0x58, 0xbc, 0x55, 0x84,
+ 0x80, 0x2a, 0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0,
+ 0x11, 0x4b, 0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87,
+ 0x26, 0x1a, 0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00,
+ 0x28, 0x3b, 0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c,
+ 0x4c, 0x63, 0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d,
+ 0x4d, 0x0b, 0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38,
+ 0x20, 0x4d, 0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86,
+ 0xba, 0xfe, 0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca,
+ 0xbf, 0x67, 0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52,
+ 0x15, 0xb8, 0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1,
+ 0x01, 0x69, 0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95,
+ 0xb2, 0xee, 0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e,
+ 0x29, 0x3f, 0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c,
+ 0xb9, 0xc8, 0x13, 0x2d, 0xec, 0x85, 0xde, 0x71,
+ 0x0d, 0x84, 0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d,
+ 0x6d, 0x3d, 0xc7, 0x36, 0x19, 0x19, 0x86, 0xde,
+ 0x7c, 0xca, 0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24,
+ 0x9c, 0xce, 0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9,
+ 0x6c, 0xc3, 0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00,
+ 0x32, 0x5e, 0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32,
+ 0xa8, 0xd5, 0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf,
+ 0x01, 0x00, 0x01,
+};
+
+const unsigned char pubkey_tpm_es256[64] = {
+ 0xfb, 0xd6, 0xba, 0x74, 0xe6, 0x6e, 0x5c, 0x87,
+ 0xef, 0x89, 0xa2, 0xe8, 0x3d, 0x0b, 0xe9, 0x69,
+ 0x2c, 0x07, 0x07, 0x7a, 0x8a, 0x1e, 0xce, 0x12,
+ 0xea, 0x3b, 0xb3, 0xf1, 0xf3, 0xd9, 0xc3, 0xe6,
+ 0x3c, 0x68, 0x51, 0x94, 0x54, 0x8d, 0xeb, 0x9f,
+ 0xb2, 0x2c, 0x66, 0x75, 0xb6, 0xb7, 0x55, 0x22,
+ 0x0d, 0x87, 0x59, 0xc4, 0x39, 0x91, 0x62, 0x17,
+ 0xc2, 0xc3, 0x53, 0xa5, 0x26, 0x97, 0x4f, 0x2d
+};
+
+const unsigned char id[64] = {
+ 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5,
+ 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53,
+ 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f,
+ 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68,
+ 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c,
+ 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90,
+ 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c,
+ 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25,
+};
+
+const unsigned char id_tpm_rs256[32] = {
+ 0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29, 0xe5, 0x3e,
+ 0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a, 0x4f, 0x03,
+ 0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a, 0x6b, 0x02,
+ 0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e, 0x38, 0x1a
+};
+
+const unsigned char id_tpm_es256[32] = {
+ 0xa8, 0xdf, 0x03, 0xf7, 0xbf, 0x39, 0x51, 0x94,
+ 0x95, 0x8f, 0xa4, 0x84, 0x97, 0x30, 0xbc, 0x3c,
+ 0x7e, 0x1c, 0x99, 0x91, 0x4d, 0xae, 0x6d, 0xfb,
+ 0xdf, 0x53, 0xb5, 0xb6, 0x1f, 0x3a, 0x4e, 0x6a
+};
+
+const unsigned char attstmt_tpm_rs256[4034] = {
+ 0xa6, 0x63, 0x61, 0x6c, 0x67, 0x39, 0xff, 0xfe,
+ 0x63, 0x73, 0x69, 0x67, 0x59, 0x01, 0x00, 0x1c,
+ 0x09, 0x0d, 0x35, 0x97, 0x22, 0xfc, 0xfe, 0xc0,
+ 0x58, 0x49, 0x9e, 0xd4, 0x7e, 0x6a, 0x7d, 0xdb,
+ 0x6d, 0x20, 0x95, 0x5c, 0x0b, 0xd0, 0xd5, 0x72,
+ 0x4f, 0x15, 0x22, 0x38, 0x97, 0xb2, 0x4b, 0xd0,
+ 0xef, 0x31, 0x7c, 0xf2, 0x42, 0x19, 0x41, 0xa1,
+ 0xe2, 0xc5, 0xca, 0xc6, 0x74, 0x95, 0xcf, 0xf9,
+ 0x41, 0x75, 0x0b, 0x56, 0x39, 0x82, 0x78, 0xf6,
+ 0x59, 0xf1, 0x09, 0x96, 0x9e, 0x38, 0x7f, 0x14,
+ 0x9b, 0xf5, 0x36, 0xbb, 0x92, 0x32, 0xc4, 0x64,
+ 0xe8, 0xff, 0xb4, 0xc7, 0xcf, 0xcd, 0x17, 0x48,
+ 0x0f, 0x83, 0xd9, 0x44, 0x03, 0x35, 0x26, 0xad,
+ 0x01, 0xb7, 0x57, 0x06, 0xb3, 0x9c, 0xa0, 0x6e,
+ 0x2f, 0x58, 0xcb, 0x5c, 0xaa, 0x7c, 0xea, 0x7e,
+ 0x3f, 0xbc, 0x76, 0xc9, 0x0e, 0x52, 0x39, 0x81,
+ 0xa9, 0x9e, 0x37, 0x14, 0x1f, 0x50, 0x6a, 0x4f,
+ 0xd7, 0xfc, 0xd4, 0xfa, 0xf2, 0x18, 0x60, 0xd5,
+ 0xc3, 0x57, 0x7d, 0x6d, 0x05, 0x28, 0x25, 0xc3,
+ 0xde, 0x86, 0x85, 0x06, 0x71, 0xfb, 0x84, 0xa2,
+ 0x07, 0xb6, 0x77, 0xc9, 0x68, 0x41, 0x53, 0x32,
+ 0x4c, 0xa8, 0x4b, 0xf7, 0x08, 0x84, 0x62, 0x6c,
+ 0x8a, 0xb6, 0xcf, 0xc1, 0xde, 0x6b, 0x61, 0xc8,
+ 0xdd, 0xc0, 0x13, 0x70, 0x22, 0x28, 0xe1, 0x0f,
+ 0x46, 0x02, 0xc6, 0xb1, 0xfa, 0x30, 0xcb, 0xec,
+ 0xd1, 0x82, 0xfa, 0x51, 0xcb, 0x71, 0x5e, 0x1f,
+ 0x1b, 0x5f, 0xe0, 0xb0, 0x02, 0x8a, 0x7c, 0x78,
+ 0xd1, 0xb7, 0x4d, 0x56, 0xb0, 0x92, 0x3e, 0xda,
+ 0xc7, 0xb1, 0x74, 0xcf, 0x6a, 0x40, 0xeb, 0x98,
+ 0x1c, 0x2e, 0xf2, 0x86, 0x76, 0xf8, 0x2e, 0x6a,
+ 0x9f, 0x77, 0x51, 0x64, 0xce, 0xdc, 0x12, 0x85,
+ 0x84, 0x6b, 0x01, 0xc8, 0xeb, 0xbc, 0x57, 0x6c,
+ 0x32, 0x26, 0xcb, 0xb2, 0x84, 0x02, 0x2a, 0x33,
+ 0x15, 0xd9, 0xe3, 0x15, 0xfc, 0x3a, 0x24, 0x63,
+ 0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63,
+ 0x78, 0x35, 0x63, 0x82, 0x59, 0x05, 0xc4, 0x30,
+ 0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x78, 0xd9,
+ 0xa8, 0xb2, 0x64, 0xf9, 0x4d, 0x28, 0x82, 0xc0,
+ 0xd3, 0x1b, 0x40, 0x3c, 0xc8, 0xd9, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x41, 0x31,
+ 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53, 0x54,
+ 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44, 0x2d,
+ 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34, 0x41,
+ 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37, 0x41,
+ 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30, 0x30,
+ 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31, 0x41,
+ 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36, 0x30,
+ 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x37,
+ 0x31, 0x35, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33,
+ 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x33, 0x32,
+ 0x31, 0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a,
+ 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+ 0x01, 0x01, 0x00, 0xca, 0xbe, 0x77, 0x9f, 0x45,
+ 0x97, 0x17, 0x8d, 0x01, 0xe1, 0x18, 0xcc, 0xf0,
+ 0xb5, 0xed, 0x9a, 0xb7, 0x36, 0xac, 0x05, 0x26,
+ 0xbe, 0x35, 0xd9, 0x5c, 0x00, 0x5c, 0x5d, 0x8b,
+ 0x6f, 0x2a, 0xb8, 0xf6, 0x02, 0x4f, 0x33, 0xfe,
+ 0x84, 0x45, 0x4c, 0x4f, 0x7a, 0xdb, 0xa9, 0x6a,
+ 0x62, 0x0f, 0x19, 0x35, 0x5d, 0xd2, 0x34, 0x1a,
+ 0x9d, 0x73, 0x55, 0xe5, 0x3e, 0x04, 0xa2, 0xd6,
+ 0xbe, 0xe7, 0x5a, 0xb9, 0x16, 0x6c, 0x55, 0x18,
+ 0xa8, 0x4b, 0xb2, 0x37, 0xb9, 0xa3, 0x87, 0xfc,
+ 0x76, 0xa8, 0x55, 0xc9, 0xe7, 0x30, 0xe5, 0x0e,
+ 0x3c, 0x7b, 0x74, 0xd2, 0x1e, 0xa8, 0x05, 0xd5,
+ 0xe2, 0xe3, 0xcb, 0xaf, 0x63, 0x33, 0x12, 0xaa,
+ 0xfd, 0x31, 0x32, 0x71, 0x4f, 0x41, 0x96, 0x05,
+ 0xb5, 0x69, 0x73, 0x45, 0xbe, 0x6f, 0x90, 0xd9,
+ 0x10, 0x36, 0xaf, 0x7a, 0x1c, 0xf1, 0x6d, 0x14,
+ 0xb0, 0x1e, 0xbb, 0xae, 0x1c, 0x35, 0xec, 0x1c,
+ 0xb5, 0x0e, 0xf6, 0x33, 0x98, 0x13, 0x4e, 0x44,
+ 0x7b, 0x5c, 0x97, 0x47, 0xed, 0x4f, 0xfe, 0xbd,
+ 0x08, 0xd2, 0xa9, 0xc6, 0xbe, 0x8c, 0x04, 0x9e,
+ 0xdc, 0x3d, 0xbe, 0x98, 0xe9, 0x2a, 0xb1, 0xf4,
+ 0xfa, 0x45, 0xf9, 0xc8, 0x9a, 0x55, 0x85, 0x26,
+ 0xfc, 0x5f, 0xad, 0x00, 0x8b, 0xc8, 0x41, 0xf2,
+ 0x86, 0x4e, 0xba, 0x55, 0x1c, 0xb2, 0x89, 0xe8,
+ 0x85, 0x6e, 0x1e, 0x02, 0x9f, 0x55, 0x70, 0xbe,
+ 0xfd, 0xe7, 0x9f, 0xba, 0x59, 0xa0, 0x2e, 0x9a,
+ 0x74, 0x11, 0xe7, 0xad, 0xa9, 0xc7, 0x7b, 0x58,
+ 0xc4, 0x16, 0xd3, 0x35, 0xcb, 0x61, 0x00, 0xec,
+ 0x36, 0x4a, 0xa3, 0x51, 0xa3, 0xdd, 0x61, 0xb6,
+ 0xd6, 0x29, 0xcb, 0x76, 0xe1, 0xab, 0x51, 0x3a,
+ 0xe8, 0xbf, 0xdb, 0x09, 0x4a, 0x39, 0x96, 0xd9,
+ 0xac, 0x8f, 0x6c, 0x62, 0xe0, 0x03, 0x23, 0x24,
+ 0xbe, 0xd4, 0x83, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0xa3, 0x82, 0x01, 0xf3, 0x30, 0x82, 0x01, 0xef,
+ 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+ 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
+ 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x6d,
+ 0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01, 0xff,
+ 0x04, 0x63, 0x30, 0x61, 0x30, 0x5f, 0x06, 0x09,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15,
+ 0x1f, 0x30, 0x52, 0x30, 0x50, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30,
+ 0x44, 0x1e, 0x42, 0x00, 0x54, 0x00, 0x43, 0x00,
+ 0x50, 0x00, 0x41, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x54, 0x00, 0x72, 0x00, 0x75, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x6d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49, 0x00,
+ 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x74, 0x00, 0x79, 0x30, 0x10, 0x06,
+ 0x03, 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07,
+ 0x06, 0x05, 0x67, 0x81, 0x05, 0x08, 0x03, 0x30,
+ 0x59, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01,
+ 0xff, 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30,
+ 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64,
+ 0x3a, 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32,
+ 0x30, 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54,
+ 0x33, 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48,
+ 0x42, 0x34, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05,
+ 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69,
+ 0x64, 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30,
+ 0x30, 0x34, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb8,
+ 0x5f, 0xd5, 0x67, 0xca, 0x92, 0xc4, 0x0e, 0xcf,
+ 0x0c, 0xd8, 0x1f, 0x6d, 0x3f, 0x03, 0x55, 0x6f,
+ 0x38, 0xa6, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd4, 0x04,
+ 0x64, 0xfc, 0x6e, 0x50, 0x0a, 0x56, 0x48, 0x0f,
+ 0x05, 0xa9, 0x00, 0xb7, 0x1d, 0x5e, 0x57, 0x08,
+ 0xd5, 0xdc, 0x30, 0x81, 0xb2, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+ 0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x81, 0x9f,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x30, 0x02, 0x86, 0x81, 0x92, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x7a, 0x63, 0x73,
+ 0x70, 0x72, 0x6f, 0x64, 0x65, 0x75, 0x73, 0x61,
+ 0x69, 0x6b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
+ 0x68, 0x2e, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x63,
+ 0x6f, 0x72, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64,
+ 0x6f, 0x77, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
+ 0x65, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x2d,
+ 0x6b, 0x65, 0x79, 0x69, 0x64, 0x2d, 0x31, 0x61,
+ 0x64, 0x62, 0x39, 0x39, 0x34, 0x61, 0x62, 0x35,
+ 0x38, 0x62, 0x65, 0x35, 0x37, 0x61, 0x30, 0x63,
+ 0x63, 0x39, 0x62, 0x39, 0x30, 0x30, 0x65, 0x37,
+ 0x38, 0x35, 0x31, 0x65, 0x31, 0x61, 0x34, 0x33,
+ 0x63, 0x30, 0x38, 0x36, 0x36, 0x30, 0x2f, 0x61,
+ 0x62, 0x64, 0x36, 0x31, 0x35, 0x66, 0x32, 0x2d,
+ 0x31, 0x35, 0x38, 0x61, 0x2d, 0x34, 0x35, 0x38,
+ 0x65, 0x2d, 0x61, 0x31, 0x35, 0x35, 0x2d, 0x37,
+ 0x63, 0x34, 0x63, 0x38, 0x63, 0x62, 0x31, 0x33,
+ 0x63, 0x36, 0x35, 0x2e, 0x63, 0x65, 0x72, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
+ 0x02, 0x01, 0x00, 0xa2, 0x10, 0xc5, 0xbf, 0x41,
+ 0xa6, 0xba, 0x8c, 0x72, 0xca, 0x0f, 0x3e, 0x5e,
+ 0x7f, 0xe2, 0xcb, 0x60, 0xb8, 0x3f, 0xfb, 0xde,
+ 0x03, 0xe2, 0xfe, 0x20, 0x29, 0xdf, 0x11, 0xf5,
+ 0xb0, 0x50, 0x6d, 0x32, 0xe8, 0x1b, 0x05, 0xad,
+ 0x6b, 0x60, 0xb5, 0xed, 0xf3, 0xa4, 0x4a, 0xea,
+ 0x09, 0xe5, 0x65, 0x7e, 0xe0, 0xd5, 0x3a, 0x6a,
+ 0xdb, 0x64, 0xb7, 0x07, 0x8f, 0xa1, 0x63, 0xb3,
+ 0x89, 0x8a, 0xac, 0x49, 0x97, 0xa0, 0x9a, 0xa3,
+ 0xd3, 0x3a, 0xc2, 0x13, 0xb2, 0xbb, 0xab, 0x0d,
+ 0xf2, 0x35, 0xc5, 0x03, 0xde, 0x1c, 0xad, 0x6a,
+ 0x03, 0x0a, 0x4c, 0xe1, 0x37, 0x8f, 0xbc, 0x13,
+ 0xc0, 0x9a, 0x17, 0xd4, 0x2e, 0x36, 0x17, 0x51,
+ 0x12, 0xb0, 0x79, 0xbf, 0x9b, 0xb3, 0xb0, 0x74,
+ 0x25, 0x81, 0x7e, 0x21, 0x31, 0xb7, 0xc2, 0x5e,
+ 0xfb, 0x36, 0xab, 0xf3, 0x7a, 0x5f, 0xa4, 0x5e,
+ 0x8f, 0x0c, 0xbd, 0xcf, 0xf5, 0x50, 0xe7, 0x0c,
+ 0x51, 0x55, 0x48, 0xe6, 0x15, 0xb6, 0xd4, 0xaf,
+ 0x95, 0x72, 0x56, 0x94, 0xf7, 0x0e, 0xd6, 0x90,
+ 0xe3, 0xd3, 0x5d, 0xbd, 0x93, 0xa1, 0xbd, 0x6c,
+ 0xe4, 0xf2, 0x39, 0x4d, 0x54, 0x74, 0xcf, 0xf5,
+ 0xeb, 0x70, 0xdb, 0x4f, 0x52, 0xcd, 0x39, 0x8f,
+ 0x11, 0x54, 0x28, 0x06, 0x29, 0x8f, 0x23, 0xde,
+ 0x9e, 0x2f, 0x7b, 0xb6, 0x5f, 0xa3, 0x89, 0x04,
+ 0x99, 0x0a, 0xf1, 0x2d, 0xf9, 0x66, 0xd3, 0x13,
+ 0x45, 0xbd, 0x6c, 0x22, 0x57, 0xf5, 0xb1, 0xb9,
+ 0xdf, 0x5b, 0x7b, 0x1a, 0x3a, 0xdd, 0x6b, 0xc7,
+ 0x35, 0x88, 0xed, 0xc4, 0x09, 0x70, 0x4e, 0x5f,
+ 0xb5, 0x3e, 0xd1, 0x0b, 0xd0, 0xca, 0xef, 0x0b,
+ 0xe9, 0x8b, 0x6f, 0xc3, 0x16, 0xc3, 0x3d, 0x79,
+ 0x06, 0xef, 0x81, 0xf0, 0x60, 0x0b, 0x32, 0xe3,
+ 0x86, 0x6b, 0x92, 0x38, 0x90, 0x62, 0xed, 0x84,
+ 0x3a, 0xb7, 0x45, 0x43, 0x2e, 0xd0, 0x3a, 0x71,
+ 0x9e, 0x80, 0xcc, 0x9c, 0xac, 0x27, 0x10, 0x91,
+ 0xb7, 0xb2, 0xbd, 0x41, 0x40, 0xa7, 0xb7, 0xcf,
+ 0xe7, 0x38, 0xca, 0x68, 0xdd, 0x62, 0x09, 0xff,
+ 0x68, 0xce, 0xba, 0xe2, 0x07, 0x49, 0x09, 0xe7,
+ 0x1f, 0xdf, 0xe6, 0x26, 0xe5, 0x0f, 0xa9, 0xbf,
+ 0x2a, 0x5b, 0x67, 0x92, 0xa1, 0x10, 0x53, 0xb2,
+ 0x7a, 0x07, 0x29, 0x9d, 0xfd, 0x6d, 0xb6, 0x3b,
+ 0x45, 0xc1, 0x94, 0xcb, 0x1c, 0xc3, 0xce, 0xf6,
+ 0x8a, 0x1a, 0x81, 0x66, 0xb0, 0xa5, 0x14, 0xc7,
+ 0x9e, 0x1f, 0x6e, 0xb6, 0xff, 0x8b, 0x90, 0x87,
+ 0x3a, 0x3f, 0xa8, 0xc2, 0x2d, 0x8f, 0x6f, 0xdb,
+ 0xb4, 0xc4, 0x14, 0x3c, 0x1d, 0x12, 0x1d, 0x6d,
+ 0xcf, 0xa6, 0x04, 0x6a, 0xa8, 0x13, 0x5e, 0xf2,
+ 0x5e, 0x77, 0x80, 0x6b, 0x85, 0x83, 0xfe, 0xbb,
+ 0xeb, 0x70, 0xcb, 0x5f, 0xe4, 0x95, 0xaa, 0x0f,
+ 0x61, 0x36, 0x7c, 0xbb, 0x22, 0x1e, 0xba, 0x98,
+ 0x43, 0x52, 0x33, 0xae, 0xed, 0x5d, 0x10, 0x2c,
+ 0xb3, 0xa9, 0x31, 0x8e, 0x60, 0x54, 0xaf, 0x40,
+ 0x6d, 0x2e, 0x18, 0xc2, 0x6a, 0xf4, 0x7b, 0x9a,
+ 0x73, 0x0f, 0x58, 0x69, 0x23, 0xbb, 0xc4, 0x84,
+ 0x53, 0x30, 0xe2, 0xd6, 0x1e, 0x10, 0xc1, 0xec,
+ 0x82, 0x13, 0xab, 0x53, 0x86, 0xa2, 0xb9, 0xda,
+ 0xbb, 0x3a, 0xa2, 0xbe, 0xb0, 0x10, 0x99, 0x0e,
+ 0xe5, 0x9c, 0xc9, 0xf1, 0xce, 0x76, 0x46, 0xea,
+ 0x86, 0xaa, 0x36, 0x83, 0x99, 0x09, 0x9b, 0x30,
+ 0xd3, 0x26, 0xc7, 0xdf, 0x66, 0xc7, 0xf0, 0xdd,
+ 0x08, 0x09, 0x15, 0x15, 0x21, 0x49, 0x46, 0xd8,
+ 0x8a, 0x66, 0xca, 0x62, 0x9c, 0x79, 0x1d, 0x81,
+ 0xea, 0x5d, 0x82, 0xb0, 0xa6, 0x6b, 0x5c, 0xf5,
+ 0xb8, 0x8c, 0xf6, 0x16, 0x01, 0x2c, 0xf8, 0x27,
+ 0xf8, 0xcf, 0x88, 0xfe, 0xf3, 0xa4, 0xfc, 0x17,
+ 0x97, 0xe7, 0x07, 0x59, 0x06, 0xef, 0x30, 0x82,
+ 0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x13, 0x33, 0x00, 0x00,
+ 0x02, 0x39, 0xf9, 0xbb, 0x6a, 0x1d, 0x49, 0x64,
+ 0x47, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
+ 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e,
+ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
+ 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e,
+ 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+ 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36,
+ 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+ 0x66, 0x74, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x52,
+ 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x32, 0x30, 0x31, 0x34, 0x30, 0x1e,
+ 0x17, 0x0d, 0x31, 0x39, 0x30, 0x33, 0x32, 0x31,
+ 0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x17,
+ 0x0d, 0x32, 0x35, 0x30, 0x33, 0x32, 0x31, 0x32,
+ 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x30, 0x41,
+ 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53,
+ 0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44,
+ 0x2d, 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34,
+ 0x41, 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37,
+ 0x41, 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30,
+ 0x30, 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31,
+ 0x41, 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36,
+ 0x30, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+ 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02,
+ 0x01, 0x00, 0xdb, 0xe2, 0x23, 0xf9, 0x86, 0x8f,
+ 0xa9, 0x71, 0x9f, 0x8b, 0xf9, 0x7c, 0xe9, 0x45,
+ 0x2d, 0x59, 0x56, 0x5e, 0x96, 0xf4, 0xdd, 0x9a,
+ 0x12, 0xcd, 0x90, 0x1a, 0x0c, 0xb5, 0x03, 0xbf,
+ 0x09, 0xbe, 0xbf, 0xf7, 0x55, 0x52, 0xe8, 0x39,
+ 0x4c, 0xbe, 0x2a, 0x28, 0x88, 0x78, 0x39, 0xa7,
+ 0xcb, 0xf9, 0x4c, 0x55, 0xd2, 0x31, 0x96, 0x3b,
+ 0x48, 0xa2, 0xf3, 0xf6, 0xd3, 0x1a, 0x81, 0x7f,
+ 0x90, 0x62, 0xab, 0xec, 0x5a, 0xc7, 0xa0, 0x7f,
+ 0x81, 0x32, 0x27, 0x9b, 0x29, 0x75, 0x7d, 0x1e,
+ 0x96, 0xc5, 0xfa, 0x0e, 0x7c, 0xe0, 0x60, 0x96,
+ 0x7a, 0xca, 0x94, 0xba, 0xe6, 0xb2, 0x69, 0xdd,
+ 0xc4, 0x7d, 0xbb, 0xd3, 0xc4, 0xb4, 0x6e, 0x00,
+ 0x86, 0x1f, 0x9d, 0x25, 0xe8, 0xae, 0xc7, 0x10,
+ 0x84, 0xdc, 0xc0, 0x34, 0x24, 0x6e, 0xf7, 0xfc,
+ 0xdd, 0x3d, 0x32, 0x7a, 0x43, 0x96, 0xd6, 0xc8,
+ 0x7b, 0xf4, 0x9b, 0x3d, 0xa7, 0x1e, 0xba, 0x4d,
+ 0xd0, 0x3b, 0x3d, 0x84, 0x9a, 0xd1, 0x25, 0x22,
+ 0x5d, 0x00, 0x44, 0xb0, 0x59, 0xb7, 0x40, 0xc5,
+ 0xa3, 0x53, 0x53, 0xaf, 0x8f, 0x9e, 0xfd, 0x8f,
+ 0x1e, 0x02, 0xd3, 0x4f, 0xf7, 0x09, 0xce, 0xc5,
+ 0xc6, 0x71, 0x5c, 0xe9, 0xe8, 0x7a, 0xb5, 0x6b,
+ 0xa4, 0xbf, 0x0b, 0xd9, 0xb6, 0xfa, 0x24, 0xb0,
+ 0xcd, 0x52, 0x22, 0x1d, 0x7e, 0xe8, 0x15, 0x2f,
+ 0x1e, 0x5e, 0xa2, 0xec, 0xd3, 0xa8, 0x02, 0x77,
+ 0xb9, 0x55, 0x9a, 0xcf, 0xcc, 0xd7, 0x08, 0x20,
+ 0xa5, 0xda, 0x39, 0x9a, 0x30, 0x76, 0x90, 0x37,
+ 0xa7, 0x60, 0xdf, 0x18, 0x12, 0x65, 0x17, 0xaa,
+ 0xdd, 0x48, 0xd5, 0x12, 0x1d, 0x4c, 0x83, 0x5d,
+ 0x81, 0x07, 0x1d, 0x18, 0x81, 0x40, 0x55, 0x60,
+ 0x8f, 0xa3, 0x6b, 0x34, 0x1e, 0xd5, 0xe6, 0xcf,
+ 0x52, 0x73, 0x77, 0x4a, 0x50, 0x4f, 0x1b, 0x0f,
+ 0x39, 0xc3, 0x0d, 0x16, 0xf9, 0xbb, 0x4c, 0x77,
+ 0xf6, 0x4e, 0xac, 0x9c, 0xfe, 0xe8, 0xbb, 0x52,
+ 0xa5, 0x0a, 0x0e, 0x9b, 0xf0, 0x0d, 0xef, 0xfb,
+ 0x6f, 0x89, 0x34, 0x7d, 0x47, 0xec, 0x14, 0x6a,
+ 0xf4, 0x0a, 0xe1, 0x60, 0x44, 0x73, 0x7b, 0xa0,
+ 0xab, 0x5b, 0x8c, 0x43, 0xa6, 0x05, 0x42, 0x61,
+ 0x46, 0xaa, 0x1c, 0xf5, 0xec, 0x2c, 0x86, 0x85,
+ 0x21, 0x99, 0xdf, 0x45, 0x8e, 0xf4, 0xd1, 0x1e,
+ 0xfb, 0xcd, 0x9b, 0x94, 0x32, 0xe0, 0xa0, 0xcc,
+ 0x4f, 0xad, 0xae, 0x44, 0x8b, 0x86, 0x27, 0x91,
+ 0xfe, 0x60, 0x9f, 0xf2, 0x63, 0x30, 0x6c, 0x5d,
+ 0x8d, 0xbc, 0xab, 0xd4, 0xf5, 0xa2, 0xb2, 0x74,
+ 0xe8, 0xd4, 0x95, 0xf2, 0xd6, 0x03, 0x8b, 0xc9,
+ 0xa3, 0x52, 0xe7, 0x63, 0x05, 0x64, 0x50, 0xe5,
+ 0x0a, 0x6a, 0xa0, 0x6c, 0x50, 0xcd, 0x37, 0x98,
+ 0xa8, 0x87, 0x02, 0x38, 0x5b, 0x6c, 0x02, 0x69,
+ 0x3d, 0x1f, 0x95, 0x74, 0x4d, 0x46, 0x76, 0x2a,
+ 0x9d, 0x62, 0xd4, 0xc7, 0x1b, 0xf9, 0x31, 0xa6,
+ 0x51, 0xee, 0x7b, 0xc8, 0xe4, 0x6e, 0x3a, 0xcf,
+ 0x4f, 0x4f, 0x49, 0x8a, 0xf5, 0x4f, 0x25, 0x93,
+ 0x23, 0x02, 0xef, 0x79, 0xa6, 0x27, 0xbe, 0x5a,
+ 0xe7, 0x74, 0xb7, 0xd7, 0xa8, 0xc1, 0xae, 0x55,
+ 0x88, 0xa4, 0xc7, 0x4d, 0xb7, 0x62, 0xf0, 0xf9,
+ 0x5b, 0xbf, 0x47, 0x5b, 0xfe, 0xcc, 0x0b, 0x89,
+ 0x19, 0x65, 0x4b, 0x6f, 0xdf, 0x4f, 0x7d, 0x4d,
+ 0x96, 0x42, 0x0d, 0x2a, 0xa1, 0xbd, 0x3e, 0x70,
+ 0x92, 0xba, 0xc8, 0x59, 0xd5, 0x1d, 0x3a, 0x98,
+ 0x53, 0x75, 0xa6, 0x32, 0xc8, 0x72, 0x03, 0x46,
+ 0x5f, 0x5c, 0x13, 0xa4, 0xdb, 0xc7, 0x55, 0x35,
+ 0x22, 0x0d, 0xc6, 0x17, 0x85, 0xbd, 0x46, 0x4b,
+ 0xfa, 0x1e, 0x49, 0xc2, 0xfe, 0x1e, 0xf9, 0x62,
+ 0x89, 0x56, 0x84, 0xdf, 0xa0, 0xfb, 0xfd, 0x93,
+ 0xa4, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+ 0x82, 0x01, 0x8e, 0x30, 0x82, 0x01, 0x8a, 0x30,
+ 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+ 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30,
+ 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x14,
+ 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+ 0x01, 0x82, 0x37, 0x15, 0x24, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x08, 0x03, 0x30, 0x16, 0x06, 0x03,
+ 0x55, 0x1d, 0x20, 0x04, 0x0f, 0x30, 0x0d, 0x30,
+ 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
+ 0x82, 0x37, 0x15, 0x1f, 0x30, 0x12, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+ 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0xb8, 0x5f, 0xd5, 0x67, 0xca,
+ 0x92, 0xc4, 0x0e, 0xcf, 0x0c, 0xd8, 0x1f, 0x6d,
+ 0x3f, 0x03, 0x55, 0x6f, 0x38, 0xa6, 0x51, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0x7a, 0x8c, 0x0a, 0xce,
+ 0x2f, 0x48, 0x62, 0x17, 0xe2, 0x94, 0xd1, 0xae,
+ 0x55, 0xc1, 0x52, 0xec, 0x71, 0x74, 0xa4, 0x56,
+ 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
+ 0x69, 0x30, 0x67, 0x30, 0x65, 0xa0, 0x63, 0xa0,
+ 0x61, 0x86, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x6f,
+ 0x70, 0x73, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d,
+ 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+ 0x25, 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32,
+ 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30,
+ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25,
+ 0x32, 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x7d, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71,
+ 0x30, 0x6f, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x61,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+ 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+ 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x70, 0x6b, 0x69, 0x6f, 0x70, 0x73, 0x2f,
+ 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x4d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x25,
+ 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32, 0x30,
+ 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43,
+ 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32,
+ 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63, 0x72,
+ 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x03, 0x82, 0x02, 0x01, 0x00, 0x41, 0xaa, 0xfe,
+ 0x28, 0x6c, 0xf7, 0x6b, 0x53, 0xde, 0x77, 0xc0,
+ 0x80, 0x50, 0x94, 0xd9, 0xdb, 0x46, 0x8e, 0x6a,
+ 0x93, 0xa9, 0x10, 0x37, 0x27, 0x1f, 0xf5, 0x70,
+ 0xf1, 0xa8, 0xcf, 0xa1, 0x45, 0x86, 0x2a, 0xdd,
+ 0x8f, 0xb8, 0xb5, 0xc1, 0xe6, 0xcf, 0x8a, 0xfa,
+ 0x32, 0xa1, 0x4b, 0xb7, 0xa4, 0xbf, 0x0a, 0x48,
+ 0xcb, 0x42, 0x63, 0x71, 0xc1, 0x96, 0xb9, 0x3a,
+ 0x37, 0x84, 0x0e, 0x24, 0x39, 0xeb, 0x58, 0xce,
+ 0x3d, 0xb7, 0xa9, 0x44, 0x92, 0x59, 0xb9, 0xff,
+ 0xdb, 0x18, 0xbe, 0x6a, 0x5e, 0xe7, 0xce, 0xef,
+ 0xb8, 0x40, 0x53, 0xaf, 0xc1, 0x9b, 0xfb, 0x42,
+ 0x99, 0x7e, 0x9d, 0x05, 0x2b, 0x71, 0x0a, 0x7a,
+ 0x7a, 0x44, 0xd1, 0x31, 0xca, 0xf0, 0x5f, 0x74,
+ 0x85, 0xa9, 0xe2, 0xbc, 0xc8, 0x0c, 0xad, 0x57,
+ 0xd1, 0xe9, 0x48, 0x90, 0x88, 0x57, 0x86, 0xd7,
+ 0xc5, 0xc9, 0xe6, 0xb2, 0x5e, 0x5f, 0x13, 0xdc,
+ 0x10, 0x7f, 0xdf, 0x63, 0x8a, 0xd5, 0x9e, 0x90,
+ 0xc2, 0x75, 0x53, 0x1e, 0x68, 0x17, 0x2b, 0x03,
+ 0x29, 0x15, 0x03, 0xc5, 0x8c, 0x66, 0x3e, 0xae,
+ 0xbd, 0x4a, 0x32, 0x7e, 0x59, 0x89, 0x0b, 0x84,
+ 0xc2, 0xd9, 0x90, 0xfa, 0x02, 0x22, 0x90, 0x8d,
+ 0x9c, 0xb6, 0x0c, 0x4d, 0xe1, 0x28, 0x76, 0xd7,
+ 0x82, 0xc3, 0x36, 0xc2, 0xa3, 0x2a, 0x52, 0xe5,
+ 0xfe, 0x3c, 0x8f, 0xe3, 0x4b, 0xda, 0x6a, 0xdb,
+ 0xc0, 0x7a, 0x3c, 0x57, 0xfa, 0x85, 0x8f, 0xfb,
+ 0x62, 0xc3, 0xa1, 0x38, 0xce, 0x84, 0xf2, 0xba,
+ 0x12, 0xf4, 0x30, 0x2a, 0x4a, 0x94, 0xa9, 0x35,
+ 0x2c, 0x7d, 0x11, 0xc7, 0x68, 0x1f, 0x47, 0xaa,
+ 0x57, 0x43, 0x06, 0x70, 0x79, 0x8c, 0xb6, 0x3b,
+ 0x5d, 0x57, 0xf3, 0xf3, 0xc0, 0x2c, 0xc5, 0xde,
+ 0x41, 0x99, 0xf6, 0xdd, 0x55, 0x8a, 0xe4, 0x13,
+ 0xca, 0xc9, 0xec, 0x69, 0x93, 0x13, 0x48, 0xf0,
+ 0x5f, 0xda, 0x2e, 0xfd, 0xfb, 0xa9, 0x1b, 0x92,
+ 0xde, 0x49, 0x71, 0x37, 0x8c, 0x3f, 0xc2, 0x08,
+ 0x0a, 0x83, 0x25, 0xf1, 0x6e, 0x0a, 0xe3, 0x55,
+ 0x85, 0x96, 0x9a, 0x2d, 0xa2, 0xc0, 0xa1, 0xee,
+ 0xfe, 0x23, 0x3b, 0x69, 0x22, 0x03, 0xfd, 0xcc,
+ 0x8a, 0xdd, 0xb4, 0x53, 0x8d, 0x84, 0xa6, 0xac,
+ 0xe0, 0x1e, 0x07, 0xe5, 0xd7, 0xf9, 0xcb, 0xb9,
+ 0xe3, 0x9a, 0xb7, 0x84, 0x70, 0xa1, 0x93, 0xd6,
+ 0x02, 0x1e, 0xfe, 0xdb, 0x28, 0x7c, 0xf7, 0xd4,
+ 0x62, 0x6f, 0x80, 0x75, 0xc8, 0xd8, 0x35, 0x26,
+ 0x0c, 0xcb, 0x84, 0xed, 0xbb, 0x95, 0xdf, 0x7f,
+ 0xd5, 0xbb, 0x00, 0x96, 0x97, 0x32, 0xe7, 0xba,
+ 0xe8, 0x29, 0xb5, 0x1a, 0x51, 0x81, 0xbb, 0x04,
+ 0xd1, 0x21, 0x76, 0x34, 0x6d, 0x1e, 0x93, 0x96,
+ 0x1f, 0x96, 0x53, 0x5f, 0x5c, 0x9e, 0xf3, 0x9d,
+ 0x82, 0x1c, 0x39, 0x36, 0x59, 0xae, 0xc9, 0x3c,
+ 0x53, 0x4a, 0x67, 0x65, 0x6e, 0xbf, 0xa6, 0xac,
+ 0x3e, 0xda, 0xb2, 0xa7, 0x63, 0x07, 0x17, 0xe1,
+ 0x5b, 0xda, 0x6a, 0x31, 0x9f, 0xfb, 0xb4, 0xea,
+ 0xa1, 0x97, 0x08, 0x6e, 0xb2, 0x68, 0xf3, 0x72,
+ 0x76, 0x99, 0xe8, 0x00, 0x46, 0x88, 0x26, 0xe1,
+ 0x3c, 0x07, 0x2b, 0x78, 0x49, 0xda, 0x79, 0x3a,
+ 0xbd, 0x6f, 0xca, 0x5c, 0xa0, 0xa8, 0xed, 0x34,
+ 0xcc, 0xdb, 0x13, 0xe2, 0x51, 0x9b, 0x3d, 0x03,
+ 0xac, 0xc7, 0xf6, 0x32, 0xe1, 0x11, 0x5d, 0xe1,
+ 0xc5, 0xfd, 0x9e, 0x7a, 0xcd, 0x06, 0xb9, 0xe6,
+ 0xfc, 0xe0, 0x03, 0x31, 0xf4, 0x4a, 0xa9, 0x3b,
+ 0x79, 0x01, 0xb0, 0x64, 0x68, 0x9f, 0x6e, 0x76,
+ 0xa1, 0xcc, 0xec, 0x17, 0x41, 0x9d, 0xd4, 0x5b,
+ 0x4e, 0x9d, 0xe5, 0x46, 0xd4, 0x6b, 0x60, 0x2a,
+ 0x23, 0xb5, 0x7a, 0x89, 0x7c, 0x27, 0x96, 0x65,
+ 0x97, 0x56, 0xec, 0x98, 0xe3, 0x67, 0x70, 0x75,
+ 0x62, 0x41, 0x72, 0x65, 0x61, 0x59, 0x01, 0x36,
+ 0x00, 0x01, 0x00, 0x0b, 0x00, 0x06, 0x04, 0x72,
+ 0x00, 0x20, 0x9d, 0xff, 0xcb, 0xf3, 0x6c, 0x38,
+ 0x3a, 0xe6, 0x99, 0xfb, 0x98, 0x68, 0xdc, 0x6d,
+ 0xcb, 0x89, 0xd7, 0x15, 0x38, 0x84, 0xbe, 0x28,
+ 0x03, 0x92, 0x2c, 0x12, 0x41, 0x58, 0xbf, 0xad,
+ 0x22, 0xae, 0x00, 0x10, 0x00, 0x10, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc5, 0xb6,
+ 0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99,
+ 0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90,
+ 0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1,
+ 0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27,
+ 0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80,
+ 0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34,
+ 0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee,
+ 0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b,
+ 0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a,
+ 0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3,
+ 0x07, 0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a,
+ 0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b,
+ 0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a,
+ 0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b,
+ 0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63,
+ 0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b,
+ 0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d,
+ 0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe,
+ 0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67,
+ 0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8,
+ 0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69,
+ 0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee,
+ 0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f,
+ 0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8,
+ 0x13, 0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84,
+ 0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d,
+ 0xc7, 0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca,
+ 0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce,
+ 0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3,
+ 0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e,
+ 0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5,
+ 0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x68, 0x63,
+ 0x65, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x58,
+ 0xa1, 0xff, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00,
+ 0x22, 0x00, 0x0b, 0xdb, 0x1f, 0x74, 0x21, 0x4f,
+ 0xa9, 0x0d, 0x90, 0x64, 0xa2, 0x33, 0xbe, 0x3f,
+ 0xf1, 0x95, 0xb0, 0x4e, 0x3f, 0x02, 0xdc, 0xad,
+ 0xb0, 0x05, 0x13, 0xe6, 0x32, 0x5f, 0xed, 0x90,
+ 0x2c, 0xad, 0xc0, 0x00, 0x14, 0x58, 0x52, 0x07,
+ 0x5d, 0x64, 0x6c, 0x1f, 0xd1, 0x13, 0x7f, 0xc3,
+ 0x74, 0xf6, 0x4b, 0xe3, 0xa0, 0x2e, 0xb7, 0x71,
+ 0xda, 0x00, 0x00, 0x00, 0x00, 0x29, 0x3c, 0x64,
+ 0xdf, 0x95, 0x38, 0xba, 0x73, 0xe3, 0x57, 0x61,
+ 0xa0, 0x01, 0x24, 0x01, 0x08, 0xc9, 0xd6, 0xea,
+ 0x60, 0xe4, 0x00, 0x22, 0x00, 0x0b, 0xe1, 0x86,
+ 0xbb, 0x79, 0x27, 0xe5, 0x01, 0x19, 0x90, 0xb3,
+ 0xe9, 0x08, 0xb0, 0xee, 0xfa, 0x3a, 0x67, 0xa9,
+ 0xf3, 0xc8, 0x9e, 0x03, 0x41, 0x07, 0x75, 0x60,
+ 0xbc, 0x94, 0x0c, 0x2a, 0xb7, 0xad, 0x00, 0x22,
+ 0x00, 0x0b, 0x35, 0xb1, 0x72, 0xd6, 0x3c, 0xe9,
+ 0x85, 0xe8, 0x66, 0xed, 0x10, 0x7a, 0x5c, 0xa3,
+ 0xe6, 0xd9, 0x4d, 0xf0, 0x52, 0x69, 0x26, 0x14,
+ 0xb4, 0x36, 0x7e, 0xad, 0x76, 0x9e, 0x58, 0x68,
+ 0x3e, 0x91
+};
+
+const unsigned char attstmt_tpm_es256[3841] = {
+ 0xa6, 0x63, 0x61, 0x6c, 0x67, 0x39, 0xff, 0xfe,
+ 0x63, 0x73, 0x69, 0x67, 0x59, 0x01, 0x00, 0x6d,
+ 0x11, 0x61, 0x1f, 0x45, 0xb9, 0x7f, 0x65, 0x6f,
+ 0x97, 0x46, 0xfe, 0xbb, 0x8a, 0x98, 0x07, 0xa3,
+ 0xbc, 0x67, 0x5c, 0xd7, 0x65, 0xa4, 0xf4, 0x6c,
+ 0x5b, 0x37, 0x75, 0xa4, 0x7f, 0x08, 0x52, 0xeb,
+ 0x1e, 0x12, 0xe2, 0x78, 0x8c, 0x7d, 0x94, 0xab,
+ 0x7b, 0xed, 0x05, 0x17, 0x67, 0x7e, 0xaa, 0x02,
+ 0x89, 0x6d, 0xe8, 0x6d, 0x43, 0x30, 0x99, 0xc6,
+ 0xf9, 0x59, 0xe5, 0x82, 0x3c, 0x56, 0x4e, 0x77,
+ 0x11, 0x25, 0xe4, 0x43, 0x6a, 0xae, 0x92, 0x4f,
+ 0x60, 0x92, 0x50, 0xf9, 0x65, 0x0e, 0x44, 0x38,
+ 0x3d, 0xf7, 0xaf, 0x66, 0x89, 0xc7, 0xe6, 0xe6,
+ 0x01, 0x07, 0x9e, 0x90, 0xfd, 0x6d, 0xaa, 0x35,
+ 0x51, 0x51, 0xbf, 0x54, 0x13, 0x95, 0xc2, 0x17,
+ 0xfa, 0x32, 0x0f, 0xa7, 0x82, 0x17, 0x58, 0x6c,
+ 0x3d, 0xea, 0x88, 0xd8, 0x64, 0xc7, 0xf8, 0xc2,
+ 0xd6, 0x1c, 0xbb, 0xea, 0x1e, 0xb3, 0xd9, 0x4c,
+ 0xa7, 0xce, 0x18, 0x1e, 0xcb, 0x42, 0x5f, 0xbf,
+ 0x44, 0xe7, 0xf1, 0x22, 0xe0, 0x5b, 0xeb, 0xff,
+ 0xb6, 0x1e, 0x6f, 0x60, 0x12, 0x16, 0x63, 0xfe,
+ 0xab, 0x5e, 0x31, 0x13, 0xdb, 0x72, 0xc6, 0x9a,
+ 0xf8, 0x8f, 0x19, 0x6b, 0x2e, 0xaf, 0x7d, 0xca,
+ 0x9f, 0xbc, 0x6b, 0x1a, 0x8b, 0x5e, 0xe3, 0x9e,
+ 0xaa, 0x8c, 0x79, 0x9c, 0x4e, 0xed, 0xe4, 0xff,
+ 0x3d, 0x12, 0x79, 0x90, 0x09, 0x61, 0x97, 0x67,
+ 0xbf, 0x04, 0xac, 0x37, 0xea, 0xa9, 0x1f, 0x9f,
+ 0x52, 0x64, 0x0b, 0xeb, 0xc3, 0x61, 0xd4, 0x13,
+ 0xb0, 0x84, 0xf1, 0x3c, 0x74, 0x83, 0xcc, 0xa8,
+ 0x1c, 0x14, 0xe6, 0x9d, 0xfe, 0xec, 0xee, 0xa1,
+ 0xd2, 0xc2, 0x0a, 0xa6, 0x36, 0x08, 0xbb, 0x17,
+ 0xa5, 0x7b, 0x53, 0x34, 0x0e, 0xc9, 0x09, 0xe5,
+ 0x10, 0xa6, 0x85, 0x01, 0x71, 0x66, 0xff, 0xd0,
+ 0x6d, 0x4b, 0x93, 0xdb, 0x81, 0x25, 0x01, 0x63,
+ 0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63,
+ 0x78, 0x35, 0x63, 0x82, 0x59, 0x05, 0xc4, 0x30,
+ 0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x30, 0xcd,
+ 0xf2, 0x7e, 0x81, 0xc0, 0x43, 0x85, 0xa2, 0xd7,
+ 0x29, 0xef, 0xf7, 0x9f, 0xa5, 0x2b, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x41, 0x31,
+ 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53, 0x54,
+ 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44, 0x2d,
+ 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34, 0x41,
+ 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37, 0x41,
+ 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30, 0x30,
+ 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31, 0x41,
+ 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36, 0x30,
+ 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31,
+ 0x30, 0x32, 0x31, 0x35, 0x30, 0x36, 0x35, 0x33,
+ 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30,
+ 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 0x5a,
+ 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+ 0x01, 0x01, 0x00, 0xdb, 0xd5, 0x9a, 0xfc, 0x09,
+ 0xa7, 0xc4, 0xa5, 0x5f, 0xbe, 0x5f, 0xa2, 0xeb,
+ 0xd6, 0x8e, 0xed, 0xc5, 0x67, 0xa6, 0xa7, 0xd9,
+ 0xb2, 0x46, 0xc6, 0xe0, 0xae, 0x0c, 0x02, 0x25,
+ 0x0a, 0xf2, 0xc5, 0x96, 0xdc, 0xb7, 0x0e, 0xb9,
+ 0x86, 0xd3, 0x51, 0xbb, 0x63, 0xf0, 0x4f, 0x8a,
+ 0x5e, 0xd7, 0xf7, 0xff, 0xbb, 0x29, 0xbd, 0x58,
+ 0xcf, 0x75, 0x02, 0x39, 0xcb, 0x80, 0xf1, 0xd4,
+ 0xb6, 0x75, 0x67, 0x2f, 0x27, 0x4d, 0x0c, 0xcc,
+ 0x18, 0x59, 0x87, 0xfa, 0x51, 0xd1, 0x80, 0xb5,
+ 0x1a, 0xac, 0xac, 0x29, 0x51, 0xcf, 0x27, 0xaa,
+ 0x74, 0xac, 0x3e, 0x59, 0x56, 0x67, 0xe4, 0x42,
+ 0xe8, 0x30, 0x35, 0xb2, 0xf6, 0x27, 0x91, 0x62,
+ 0x60, 0x42, 0x42, 0x12, 0xde, 0xfe, 0xdd, 0xee,
+ 0xe8, 0xa8, 0x82, 0xf9, 0xb1, 0x08, 0xd5, 0x8d,
+ 0x57, 0x9a, 0x29, 0xb9, 0xb4, 0xe9, 0x19, 0x1e,
+ 0x33, 0x7d, 0x37, 0xa0, 0xce, 0x2e, 0x53, 0x13,
+ 0x39, 0xb6, 0x12, 0x61, 0x63, 0xbf, 0xd3, 0x42,
+ 0xeb, 0x6f, 0xed, 0xc1, 0x8e, 0x26, 0xba, 0x7d,
+ 0x8b, 0x37, 0x7c, 0xbb, 0x42, 0x1e, 0x56, 0x76,
+ 0xda, 0xdb, 0x35, 0x6b, 0x80, 0xe1, 0x8e, 0x00,
+ 0xac, 0xd2, 0xfc, 0x22, 0x96, 0x14, 0x0c, 0xf4,
+ 0xe4, 0xc5, 0xad, 0x14, 0xb7, 0x4d, 0x46, 0x63,
+ 0x30, 0x79, 0x3a, 0x7c, 0x33, 0xb5, 0xe5, 0x2e,
+ 0xbb, 0x5f, 0xca, 0xf2, 0x75, 0xe3, 0x4e, 0x99,
+ 0x64, 0x1b, 0x26, 0x99, 0x60, 0x1a, 0x79, 0xcc,
+ 0x30, 0x2c, 0xb3, 0x4c, 0x59, 0xf7, 0x77, 0x59,
+ 0xd5, 0x90, 0x70, 0x21, 0x79, 0x8c, 0x1f, 0x79,
+ 0x0a, 0x12, 0x8b, 0x3b, 0x37, 0x2d, 0x97, 0x39,
+ 0x89, 0x92, 0x0c, 0x44, 0x7c, 0xe9, 0x9f, 0xce,
+ 0x6d, 0xad, 0xc5, 0xae, 0xea, 0x8e, 0x50, 0x22,
+ 0x37, 0xe0, 0xd1, 0x9e, 0xd6, 0xe6, 0xa8, 0xcc,
+ 0x21, 0xfb, 0xff, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0xa3, 0x82, 0x01, 0xf3, 0x30, 0x82, 0x01, 0xef,
+ 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+ 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
+ 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x6d,
+ 0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01, 0xff,
+ 0x04, 0x63, 0x30, 0x61, 0x30, 0x5f, 0x06, 0x09,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15,
+ 0x1f, 0x30, 0x52, 0x30, 0x50, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30,
+ 0x44, 0x1e, 0x42, 0x00, 0x54, 0x00, 0x43, 0x00,
+ 0x50, 0x00, 0x41, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x54, 0x00, 0x72, 0x00, 0x75, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x6d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49, 0x00,
+ 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x74, 0x00, 0x79, 0x30, 0x10, 0x06,
+ 0x03, 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07,
+ 0x06, 0x05, 0x67, 0x81, 0x05, 0x08, 0x03, 0x30,
+ 0x59, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01,
+ 0xff, 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30,
+ 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64,
+ 0x3a, 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32,
+ 0x30, 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54,
+ 0x33, 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48,
+ 0x42, 0x34, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05,
+ 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69,
+ 0x64, 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30,
+ 0x30, 0x34, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x45,
+ 0x1a, 0xec, 0xfc, 0x91, 0x70, 0xf8, 0x83, 0x8b,
+ 0x9c, 0x47, 0x2f, 0x0b, 0x9f, 0x07, 0xf3, 0x2f,
+ 0x7c, 0xa2, 0x8a, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x55, 0xa6,
+ 0xee, 0xe3, 0x28, 0xdd, 0x40, 0x7f, 0x21, 0xd2,
+ 0x7b, 0x8c, 0x69, 0x2f, 0x8c, 0x08, 0x29, 0xbc,
+ 0x95, 0xb8, 0x30, 0x81, 0xb2, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+ 0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x81, 0x9f,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x30, 0x02, 0x86, 0x81, 0x92, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x7a, 0x63, 0x73,
+ 0x70, 0x72, 0x6f, 0x64, 0x65, 0x75, 0x73, 0x61,
+ 0x69, 0x6b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
+ 0x68, 0x2e, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x63,
+ 0x6f, 0x72, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64,
+ 0x6f, 0x77, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
+ 0x65, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x2d,
+ 0x6b, 0x65, 0x79, 0x69, 0x64, 0x2d, 0x31, 0x61,
+ 0x64, 0x62, 0x39, 0x39, 0x34, 0x61, 0x62, 0x35,
+ 0x38, 0x62, 0x65, 0x35, 0x37, 0x61, 0x30, 0x63,
+ 0x63, 0x39, 0x62, 0x39, 0x30, 0x30, 0x65, 0x37,
+ 0x38, 0x35, 0x31, 0x65, 0x31, 0x61, 0x34, 0x33,
+ 0x63, 0x30, 0x38, 0x36, 0x36, 0x30, 0x2f, 0x62,
+ 0x36, 0x63, 0x30, 0x64, 0x39, 0x38, 0x64, 0x2d,
+ 0x35, 0x37, 0x38, 0x61, 0x2d, 0x34, 0x62, 0x66,
+ 0x62, 0x2d, 0x61, 0x32, 0x64, 0x33, 0x2d, 0x65,
+ 0x64, 0x66, 0x65, 0x35, 0x66, 0x38, 0x32, 0x30,
+ 0x36, 0x30, 0x31, 0x2e, 0x63, 0x65, 0x72, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
+ 0x02, 0x01, 0x00, 0x2a, 0x08, 0x30, 0x1f, 0xfd,
+ 0x8f, 0x80, 0x9b, 0x4b, 0x37, 0x82, 0x61, 0x86,
+ 0x36, 0x57, 0x90, 0xb5, 0x1d, 0x1f, 0xa3, 0xae,
+ 0x68, 0xac, 0xa7, 0x96, 0x6a, 0x25, 0x5e, 0xc5,
+ 0x82, 0x7c, 0x36, 0x64, 0x58, 0x11, 0xcb, 0xa5,
+ 0xee, 0xbf, 0xc4, 0xdb, 0xa0, 0xc7, 0x82, 0x3b,
+ 0xa3, 0x85, 0x9b, 0xc4, 0xee, 0x07, 0x36, 0xd7,
+ 0xc7, 0xb6, 0x23, 0xed, 0xc2, 0x73, 0xab, 0xbe,
+ 0xbe, 0xee, 0x63, 0x17, 0xf9, 0xd7, 0x7a, 0x23,
+ 0x7b, 0xf8, 0x09, 0x7a, 0xaa, 0x7f, 0x67, 0xc3,
+ 0x04, 0x84, 0x71, 0x9b, 0x06, 0x9c, 0x07, 0x42,
+ 0x4b, 0x65, 0x41, 0x56, 0x58, 0x14, 0x92, 0xb0,
+ 0xb9, 0xaf, 0xa1, 0x39, 0xd4, 0x08, 0x2d, 0x71,
+ 0xd5, 0x6c, 0x56, 0xb9, 0x2b, 0x1e, 0xf3, 0x93,
+ 0xa5, 0xe9, 0xb2, 0x9b, 0x4d, 0x05, 0x2b, 0xbc,
+ 0xd2, 0x20, 0x57, 0x3b, 0xa4, 0x01, 0x68, 0x8c,
+ 0x23, 0x20, 0x7d, 0xbb, 0x71, 0xe4, 0x2a, 0x24,
+ 0xba, 0x75, 0x0c, 0x89, 0x54, 0x22, 0xeb, 0x0e,
+ 0xb2, 0xf4, 0xc2, 0x1f, 0x02, 0xb7, 0xe3, 0x06,
+ 0x41, 0x15, 0x6b, 0xf3, 0xc8, 0x2d, 0x5b, 0xc2,
+ 0x21, 0x82, 0x3e, 0xe8, 0x95, 0x40, 0x39, 0x9e,
+ 0x91, 0x68, 0x33, 0x0c, 0x3d, 0x45, 0xef, 0x99,
+ 0x79, 0xe6, 0x32, 0xc9, 0x00, 0x84, 0x36, 0xfb,
+ 0x0a, 0x8d, 0x41, 0x1c, 0x32, 0x64, 0x06, 0x9e,
+ 0x0f, 0xb5, 0x04, 0xcc, 0x08, 0xb1, 0xb6, 0x2b,
+ 0xcf, 0x36, 0x0f, 0x73, 0x14, 0x8e, 0x25, 0x44,
+ 0xb3, 0x0c, 0x34, 0x14, 0x96, 0x0c, 0x8a, 0x65,
+ 0xa1, 0xde, 0x8e, 0xc8, 0x9d, 0xbe, 0x66, 0xdf,
+ 0x06, 0x91, 0xca, 0x15, 0x0f, 0x92, 0xd5, 0x2a,
+ 0x0b, 0xdc, 0x4c, 0x6a, 0xf3, 0x16, 0x4a, 0x3e,
+ 0xb9, 0x76, 0xbc, 0xfe, 0x62, 0xd4, 0xa8, 0xcd,
+ 0x94, 0x78, 0x0d, 0xdd, 0x94, 0xfd, 0x5e, 0x63,
+ 0x57, 0x27, 0x05, 0x9c, 0xd0, 0x80, 0x91, 0x91,
+ 0x79, 0xe8, 0x5e, 0x18, 0x64, 0x22, 0xe4, 0x2c,
+ 0x13, 0x65, 0xa4, 0x51, 0x5a, 0x1e, 0x3b, 0x71,
+ 0x2e, 0x70, 0x9f, 0xc4, 0xa5, 0x20, 0xcd, 0xef,
+ 0xd8, 0x3f, 0xa4, 0xf5, 0x89, 0x8a, 0xa5, 0x4f,
+ 0x76, 0x2d, 0x49, 0x56, 0x00, 0x8d, 0xde, 0x40,
+ 0xba, 0x24, 0x46, 0x51, 0x38, 0xad, 0xdb, 0xc4,
+ 0x04, 0xf4, 0x6e, 0xc0, 0x29, 0x48, 0x07, 0x6a,
+ 0x1b, 0x26, 0x32, 0x0a, 0xfb, 0xea, 0x71, 0x2a,
+ 0x11, 0xfc, 0x98, 0x7c, 0x44, 0x87, 0xbc, 0x06,
+ 0x3a, 0x4d, 0xbd, 0x91, 0x63, 0x4f, 0x26, 0x48,
+ 0x54, 0x47, 0x1b, 0xbd, 0xf0, 0xf1, 0x56, 0x05,
+ 0xc5, 0x0f, 0x8f, 0x20, 0xa5, 0xcc, 0xfb, 0x76,
+ 0xb0, 0xbd, 0x83, 0xde, 0x7f, 0x39, 0x4f, 0xcf,
+ 0x61, 0x74, 0x52, 0xa7, 0x1d, 0xf6, 0xb5, 0x5e,
+ 0x4a, 0x82, 0x20, 0xc1, 0x94, 0xaa, 0x2c, 0x33,
+ 0xd6, 0x0a, 0xf9, 0x8f, 0x92, 0xc6, 0x29, 0x80,
+ 0xf5, 0xa2, 0xb1, 0xff, 0xb6, 0x2b, 0xaa, 0x04,
+ 0x00, 0x72, 0xb4, 0x12, 0xbb, 0xb1, 0xf1, 0x3c,
+ 0x88, 0xa3, 0xab, 0x49, 0x17, 0x90, 0x80, 0x59,
+ 0xa2, 0x96, 0x41, 0x69, 0x74, 0x33, 0x8a, 0x28,
+ 0x33, 0x7e, 0xb3, 0x19, 0x92, 0x28, 0xc1, 0xf0,
+ 0xd1, 0x82, 0xd5, 0x42, 0xff, 0xe7, 0xa5, 0x3f,
+ 0x1e, 0xb6, 0x4a, 0x23, 0xcc, 0x6a, 0x7f, 0x15,
+ 0x15, 0x52, 0x25, 0xb1, 0xca, 0x21, 0x95, 0x11,
+ 0x53, 0x3e, 0x1f, 0x50, 0x33, 0x12, 0x7a, 0x62,
+ 0xce, 0xcc, 0x71, 0xc2, 0x5f, 0x34, 0x47, 0xc6,
+ 0x7c, 0x71, 0xfa, 0xa0, 0x54, 0x00, 0xb2, 0xdf,
+ 0xc5, 0x54, 0xac, 0x6c, 0x53, 0xef, 0x64, 0x6b,
+ 0x08, 0x82, 0xd8, 0x16, 0x1e, 0xca, 0x40, 0xf3,
+ 0x1f, 0xdf, 0x56, 0x63, 0x10, 0xbc, 0xd7, 0xa0,
+ 0xeb, 0xee, 0xd1, 0x95, 0xe5, 0xef, 0xf1, 0x6a,
+ 0x83, 0x2d, 0x5a, 0x59, 0x06, 0xef, 0x30, 0x82,
+ 0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x13, 0x33, 0x00, 0x00,
+ 0x05, 0x23, 0xbf, 0xe8, 0xa1, 0x1a, 0x2a, 0x68,
+ 0xbd, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x23,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
+ 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e,
+ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
+ 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e,
+ 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+ 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36,
+ 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+ 0x66, 0x74, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x52,
+ 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x32, 0x30, 0x31, 0x34, 0x30, 0x1e,
+ 0x17, 0x0d, 0x32, 0x31, 0x30, 0x36, 0x30, 0x33,
+ 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 0x5a, 0x17,
+ 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30, 0x33, 0x31,
+ 0x39, 0x34, 0x30, 0x31, 0x36, 0x5a, 0x30, 0x41,
+ 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53,
+ 0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44,
+ 0x2d, 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34,
+ 0x41, 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37,
+ 0x41, 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30,
+ 0x30, 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31,
+ 0x41, 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36,
+ 0x30, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+ 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02,
+ 0x01, 0x00, 0xdb, 0x03, 0x34, 0x82, 0xfa, 0x81,
+ 0x1c, 0x84, 0x0b, 0xa0, 0x0e, 0x60, 0xd8, 0x9d,
+ 0x84, 0xf4, 0x81, 0xc4, 0xe9, 0xff, 0xcf, 0xe9,
+ 0xa3, 0x57, 0x53, 0x60, 0xa8, 0x19, 0xce, 0xbe,
+ 0xe1, 0x97, 0xee, 0x5d, 0x8c, 0x9f, 0xe4, 0xbd,
+ 0xef, 0xbd, 0x94, 0x14, 0xe4, 0x74, 0x41, 0x02,
+ 0xe9, 0x03, 0x19, 0x9f, 0xdd, 0x48, 0x2d, 0xbd,
+ 0xca, 0x26, 0x47, 0x2c, 0x01, 0x31, 0x5f, 0x34,
+ 0xef, 0x59, 0x35, 0x48, 0x36, 0x3d, 0x1e, 0xdf,
+ 0xd8, 0x13, 0xf0, 0xd0, 0x67, 0xc1, 0xb0, 0x47,
+ 0x67, 0xa2, 0xd6, 0x62, 0xc8, 0xe1, 0x00, 0x36,
+ 0x8b, 0x45, 0xf6, 0x3b, 0x96, 0x60, 0xa0, 0x45,
+ 0x26, 0xcb, 0xc7, 0x0b, 0x5b, 0x97, 0xd1, 0xaf,
+ 0x54, 0x25, 0x7a, 0x67, 0xe4, 0x2a, 0xd8, 0x9d,
+ 0x53, 0x05, 0xbd, 0x12, 0xac, 0xa2, 0x8e, 0x95,
+ 0xb4, 0x2a, 0xca, 0x89, 0x93, 0x64, 0x97, 0x25,
+ 0xdc, 0x1f, 0xa9, 0xe0, 0x55, 0x07, 0x38, 0x1d,
+ 0xee, 0x02, 0x90, 0x22, 0xf5, 0xad, 0x4e, 0x5c,
+ 0xf8, 0xc5, 0x1f, 0x9e, 0x84, 0x7e, 0x13, 0x47,
+ 0x52, 0xa2, 0x36, 0xf9, 0xf6, 0xbf, 0x76, 0x9e,
+ 0x0f, 0xdd, 0x14, 0x99, 0xb9, 0xd8, 0x5a, 0x42,
+ 0x3d, 0xd8, 0xbf, 0xdd, 0xb4, 0x9b, 0xbf, 0x6a,
+ 0x9f, 0x89, 0x13, 0x75, 0xaf, 0x96, 0xd2, 0x72,
+ 0xdf, 0xb3, 0x80, 0x6f, 0x84, 0x1a, 0x9d, 0x06,
+ 0x55, 0x09, 0x29, 0xea, 0xa7, 0x05, 0x31, 0xec,
+ 0x47, 0x3a, 0xcf, 0x3f, 0x9c, 0x2c, 0xbd, 0xd0,
+ 0x7d, 0xe4, 0x75, 0x5b, 0x33, 0xbe, 0x12, 0x86,
+ 0x09, 0xcf, 0x66, 0x9a, 0xeb, 0xf8, 0xf8, 0x72,
+ 0x91, 0x88, 0x4a, 0x5e, 0x89, 0x62, 0x6a, 0x94,
+ 0xdc, 0x48, 0x37, 0x13, 0xd8, 0x91, 0x02, 0xe3,
+ 0x42, 0x41, 0x7c, 0x2f, 0xe3, 0xb6, 0x0f, 0xb4,
+ 0x96, 0x06, 0x80, 0xca, 0x28, 0x01, 0x6f, 0x4b,
+ 0xcd, 0x28, 0xd4, 0x2c, 0x94, 0x7e, 0x40, 0x7e,
+ 0xdf, 0x01, 0xe5, 0xf2, 0x33, 0xd4, 0xda, 0xf4,
+ 0x1a, 0x17, 0xf7, 0x5d, 0xcb, 0x66, 0x2c, 0x2a,
+ 0xeb, 0xe1, 0xb1, 0x4a, 0xc3, 0x85, 0x63, 0xb2,
+ 0xac, 0xd0, 0x3f, 0x1a, 0x8d, 0xa5, 0x0c, 0xee,
+ 0x4f, 0xde, 0x74, 0x9c, 0xe0, 0x5a, 0x10, 0xc7,
+ 0xb8, 0xe4, 0xec, 0xe7, 0x73, 0xa6, 0x41, 0x42,
+ 0x37, 0xe1, 0xdf, 0xb9, 0xc7, 0xb5, 0x14, 0xa8,
+ 0x80, 0x95, 0xa0, 0x12, 0x67, 0x99, 0xf5, 0xba,
+ 0x25, 0x0a, 0x74, 0x86, 0x71, 0x9c, 0x7f, 0x59,
+ 0x97, 0xd2, 0x3f, 0x10, 0xfe, 0x6a, 0xb9, 0xe4,
+ 0x47, 0x36, 0xfb, 0x0f, 0x50, 0xee, 0xfc, 0x87,
+ 0x99, 0x7e, 0x36, 0x64, 0x1b, 0xc7, 0x13, 0xb3,
+ 0x33, 0x18, 0x71, 0xa4, 0xc3, 0xb0, 0xfc, 0x45,
+ 0x37, 0x11, 0x40, 0xb3, 0xde, 0x2c, 0x9f, 0x0a,
+ 0xcd, 0xaf, 0x5e, 0xfb, 0xd5, 0x9c, 0xea, 0xd7,
+ 0x24, 0x19, 0x3a, 0x92, 0x80, 0xa5, 0x63, 0xc5,
+ 0x3e, 0xdd, 0x51, 0xd0, 0x9f, 0xb8, 0x5e, 0xd5,
+ 0xf1, 0xfe, 0xa5, 0x93, 0xfb, 0x7f, 0xd9, 0xb8,
+ 0xb7, 0x0e, 0x0d, 0x12, 0x71, 0xf0, 0x52, 0x9d,
+ 0xe9, 0xd0, 0xd2, 0x8b, 0x38, 0x8b, 0x85, 0x83,
+ 0x98, 0x24, 0x88, 0xe8, 0x42, 0x30, 0x83, 0x12,
+ 0xef, 0x09, 0x96, 0x2f, 0x21, 0x81, 0x05, 0x30,
+ 0x0c, 0xbb, 0xba, 0x21, 0x39, 0x16, 0x12, 0xe8,
+ 0x4b, 0x7b, 0x7a, 0x66, 0xb8, 0x22, 0x2c, 0x71,
+ 0xaf, 0x59, 0xa1, 0xfc, 0x61, 0xf1, 0xb4, 0x5e,
+ 0xfc, 0x43, 0x19, 0x45, 0x6e, 0xa3, 0x45, 0xe4,
+ 0xcb, 0x66, 0x5f, 0xe0, 0x57, 0xf6, 0x0a, 0x30,
+ 0xa3, 0xd6, 0x51, 0x24, 0xc9, 0x07, 0x55, 0x82,
+ 0x4a, 0x66, 0x0e, 0x9d, 0xb2, 0x2f, 0x84, 0x56,
+ 0x6c, 0x3e, 0x71, 0xef, 0x9b, 0x35, 0x4d, 0x72,
+ 0xdc, 0x46, 0x2a, 0xe3, 0x7b, 0x13, 0x20, 0xbf,
+ 0xab, 0x77, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+ 0x82, 0x01, 0x8e, 0x30, 0x82, 0x01, 0x8a, 0x30,
+ 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+ 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30,
+ 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x14,
+ 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+ 0x01, 0x82, 0x37, 0x15, 0x24, 0x06, 0x05, 0x67,
+ 0x81, 0x05, 0x08, 0x03, 0x30, 0x16, 0x06, 0x03,
+ 0x55, 0x1d, 0x20, 0x04, 0x0f, 0x30, 0x0d, 0x30,
+ 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
+ 0x82, 0x37, 0x15, 0x1f, 0x30, 0x12, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+ 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0x45, 0x1a, 0xec, 0xfc, 0x91,
+ 0x70, 0xf8, 0x83, 0x8b, 0x9c, 0x47, 0x2f, 0x0b,
+ 0x9f, 0x07, 0xf3, 0x2f, 0x7c, 0xa2, 0x8a, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0x7a, 0x8c, 0x0a, 0xce,
+ 0x2f, 0x48, 0x62, 0x17, 0xe2, 0x94, 0xd1, 0xae,
+ 0x55, 0xc1, 0x52, 0xec, 0x71, 0x74, 0xa4, 0x56,
+ 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
+ 0x69, 0x30, 0x67, 0x30, 0x65, 0xa0, 0x63, 0xa0,
+ 0x61, 0x86, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x6f,
+ 0x70, 0x73, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d,
+ 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+ 0x25, 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32,
+ 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30,
+ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25,
+ 0x32, 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x7d, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71,
+ 0x30, 0x6f, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x61,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+ 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+ 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x70, 0x6b, 0x69, 0x6f, 0x70, 0x73, 0x2f,
+ 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x4d, 0x69,
+ 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x25,
+ 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32, 0x30,
+ 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43,
+ 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32,
+ 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63, 0x72,
+ 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x03, 0x82, 0x02, 0x01, 0x00, 0x48, 0x24, 0x32,
+ 0xe8, 0xd6, 0x38, 0xda, 0x65, 0xec, 0x1b, 0x18,
+ 0x8e, 0x37, 0x07, 0xd5, 0x18, 0x5a, 0xc8, 0xb9,
+ 0xbb, 0x24, 0x8a, 0x4d, 0xa1, 0x3c, 0x9e, 0x46,
+ 0x76, 0xcf, 0xa5, 0xdf, 0xd7, 0x61, 0xba, 0x05,
+ 0x89, 0x3c, 0x13, 0xc2, 0x1f, 0x71, 0xe3, 0xec,
+ 0x5d, 0x54, 0x9e, 0xd9, 0x01, 0x5a, 0x10, 0x3b,
+ 0x17, 0x75, 0xde, 0xa1, 0x45, 0xbf, 0x1d, 0x1b,
+ 0x41, 0x21, 0x42, 0x68, 0x22, 0x6b, 0xbb, 0xcb,
+ 0x11, 0x04, 0xd2, 0xae, 0x86, 0xcf, 0x73, 0x5a,
+ 0xf2, 0x80, 0x18, 0x00, 0xf0, 0xd6, 0x6c, 0x5a,
+ 0x1e, 0xb3, 0x4d, 0x30, 0x02, 0x4a, 0x6a, 0x03,
+ 0x36, 0x42, 0xde, 0xb2, 0x52, 0x55, 0xff, 0x71,
+ 0xeb, 0x7b, 0x8b, 0x55, 0x6c, 0xdf, 0x05, 0x35,
+ 0x47, 0x70, 0x53, 0xfb, 0x6c, 0xba, 0x06, 0xb2,
+ 0x61, 0x86, 0xdc, 0x2a, 0x64, 0x81, 0x24, 0x79,
+ 0x46, 0x73, 0x04, 0x55, 0x59, 0xed, 0xd6, 0x06,
+ 0x61, 0x15, 0xf9, 0x8d, 0x78, 0x39, 0x7b, 0x84,
+ 0x7a, 0x40, 0x45, 0x13, 0x1a, 0x91, 0x71, 0x8f,
+ 0xd1, 0x4f, 0x78, 0x10, 0x68, 0x9b, 0x15, 0x79,
+ 0x3f, 0x79, 0x2d, 0x9b, 0xc7, 0x5d, 0xa3, 0xcf,
+ 0xa9, 0x14, 0xb0, 0xc4, 0xdb, 0xa9, 0x45, 0x6a,
+ 0x6e, 0x60, 0x45, 0x0b, 0x14, 0x25, 0xc7, 0x74,
+ 0xd0, 0x36, 0xaf, 0xc5, 0xbd, 0x4f, 0x7b, 0xc0,
+ 0x04, 0x43, 0x85, 0xbb, 0x06, 0x36, 0x77, 0x26,
+ 0x02, 0x23, 0x0b, 0xf8, 0x57, 0x8f, 0x1f, 0x27,
+ 0x30, 0x95, 0xff, 0x83, 0x23, 0x2b, 0x49, 0x33,
+ 0x43, 0x62, 0x87, 0x5d, 0x27, 0x12, 0x1a, 0x68,
+ 0x7b, 0xba, 0x2d, 0xf6, 0xed, 0x2c, 0x26, 0xb5,
+ 0xbb, 0xe2, 0x6f, 0xc2, 0x61, 0x17, 0xfc, 0x72,
+ 0x14, 0x57, 0x2c, 0x2c, 0x5a, 0x92, 0x13, 0x41,
+ 0xc4, 0x7e, 0xb5, 0x64, 0x5b, 0x86, 0x57, 0x13,
+ 0x14, 0xff, 0xf5, 0x04, 0xb9, 0x3d, 0x2d, 0xc3,
+ 0xe9, 0x75, 0x1f, 0x68, 0x0b, 0xb5, 0x76, 0xe1,
+ 0x7d, 0xe3, 0xb0, 0x14, 0xa8, 0x45, 0x05, 0x98,
+ 0x81, 0x32, 0xc1, 0xf5, 0x49, 0x4d, 0x58, 0xa4,
+ 0xee, 0xd8, 0x84, 0xba, 0x65, 0x07, 0x8d, 0xf7,
+ 0x9a, 0xff, 0x7d, 0xa5, 0xbc, 0x9a, 0xed, 0x4a,
+ 0x5d, 0xa4, 0x97, 0x4b, 0x4d, 0x31, 0x90, 0xb5,
+ 0x7d, 0x28, 0x77, 0x25, 0x88, 0x1c, 0xbf, 0x78,
+ 0x22, 0xb2, 0xb5, 0x5c, 0x9a, 0xc9, 0x63, 0x17,
+ 0x96, 0xe9, 0xc2, 0x52, 0x30, 0xb8, 0x9b, 0x37,
+ 0x69, 0x1a, 0x6a, 0x66, 0x76, 0x18, 0xac, 0xc0,
+ 0x48, 0xee, 0x46, 0x5b, 0xbe, 0x6a, 0xd5, 0x72,
+ 0x07, 0xdc, 0x7d, 0x05, 0xbe, 0x76, 0x7d, 0xa5,
+ 0x5e, 0x53, 0xb5, 0x47, 0x80, 0x58, 0xf0, 0xaf,
+ 0x6f, 0x4e, 0xc0, 0xf1, 0x1e, 0x37, 0x64, 0x15,
+ 0x42, 0x96, 0x18, 0x3a, 0x89, 0xc8, 0x14, 0x48,
+ 0x89, 0x5c, 0x12, 0x88, 0x98, 0x0b, 0x7b, 0x4e,
+ 0xce, 0x1c, 0xda, 0xd5, 0xa4, 0xd3, 0x32, 0x32,
+ 0x74, 0x5b, 0xcc, 0xfd, 0x2b, 0x02, 0xfb, 0xae,
+ 0xd0, 0x5a, 0x4c, 0xc9, 0xc1, 0x35, 0x19, 0x90,
+ 0x5f, 0xca, 0x14, 0xeb, 0x4c, 0x17, 0xd7, 0xe3,
+ 0xe2, 0x5d, 0xb4, 0x49, 0xaa, 0xf0, 0x50, 0x87,
+ 0xc3, 0x20, 0x00, 0xda, 0xe9, 0x04, 0x80, 0x64,
+ 0xac, 0x9f, 0xcd, 0x26, 0x41, 0x48, 0xe8, 0x4c,
+ 0x46, 0xcc, 0x5b, 0xd7, 0xca, 0x4c, 0x1b, 0x43,
+ 0x43, 0x1e, 0xbd, 0x94, 0xe7, 0xa7, 0xa6, 0x86,
+ 0xe5, 0xd1, 0x78, 0x29, 0xa2, 0x40, 0xc5, 0xc5,
+ 0x47, 0xb6, 0x6d, 0x53, 0xde, 0xac, 0x97, 0x74,
+ 0x24, 0x57, 0xcc, 0x05, 0x93, 0xfd, 0x52, 0x35,
+ 0x29, 0xd5, 0xe0, 0xfa, 0x23, 0x0d, 0xd7, 0xaa,
+ 0x8b, 0x07, 0x4b, 0xf6, 0x64, 0xc7, 0xad, 0x3c,
+ 0xa1, 0xb5, 0xc5, 0x70, 0xaf, 0x46, 0xfe, 0x9a,
+ 0x82, 0x4d, 0x75, 0xb8, 0x6d, 0x67, 0x70, 0x75,
+ 0x62, 0x41, 0x72, 0x65, 0x61, 0x58, 0x76, 0x00,
+ 0x23, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x72, 0x00,
+ 0x20, 0x9d, 0xff, 0xcb, 0xf3, 0x6c, 0x38, 0x3a,
+ 0xe6, 0x99, 0xfb, 0x98, 0x68, 0xdc, 0x6d, 0xcb,
+ 0x89, 0xd7, 0x15, 0x38, 0x84, 0xbe, 0x28, 0x03,
+ 0x92, 0x2c, 0x12, 0x41, 0x58, 0xbf, 0xad, 0x22,
+ 0xae, 0x00, 0x10, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x10, 0x00, 0x20, 0xfb, 0xd6, 0xba, 0x74, 0xe6,
+ 0x6e, 0x5c, 0x87, 0xef, 0x89, 0xa2, 0xe8, 0x3d,
+ 0x0b, 0xe9, 0x69, 0x2c, 0x07, 0x07, 0x7a, 0x8a,
+ 0x1e, 0xce, 0x12, 0xea, 0x3b, 0xb3, 0xf1, 0xf3,
+ 0xd9, 0xc3, 0xe6, 0x00, 0x20, 0x3c, 0x68, 0x51,
+ 0x94, 0x54, 0x8d, 0xeb, 0x9f, 0xb2, 0x2c, 0x66,
+ 0x75, 0xb6, 0xb7, 0x55, 0x22, 0x0d, 0x87, 0x59,
+ 0xc4, 0x39, 0x91, 0x62, 0x17, 0xc2, 0xc3, 0x53,
+ 0xa5, 0x26, 0x97, 0x4f, 0x2d, 0x68, 0x63, 0x65,
+ 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x58, 0xa1,
+ 0xff, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00, 0x22,
+ 0x00, 0x0b, 0x73, 0xbe, 0xb7, 0x40, 0x82, 0xc0,
+ 0x49, 0x9a, 0xf7, 0xf2, 0xd0, 0x79, 0x6c, 0x88,
+ 0xf3, 0x56, 0x7b, 0x7a, 0x7d, 0xcd, 0x70, 0xd1,
+ 0xbc, 0x41, 0x88, 0x48, 0x51, 0x03, 0xf3, 0x58,
+ 0x3e, 0xb8, 0x00, 0x14, 0x9f, 0x57, 0x39, 0x67,
+ 0xa8, 0x7b, 0xd8, 0xf6, 0x9e, 0x75, 0xc9, 0x85,
+ 0xab, 0xe3, 0x55, 0xc7, 0x9c, 0xf6, 0xd8, 0x4f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x1c, 0x12,
+ 0xfd, 0xc6, 0x05, 0xc6, 0x2b, 0xf5, 0xe9, 0x88,
+ 0x01, 0x1f, 0x70, 0x8d, 0x98, 0x2a, 0x04, 0x21,
+ 0x30, 0x00, 0x22, 0x00, 0x0b, 0xf4, 0xfd, 0x9a,
+ 0x33, 0x55, 0x21, 0x08, 0x27, 0x48, 0x55, 0x01,
+ 0x56, 0xf9, 0x0b, 0x4e, 0x47, 0x55, 0x08, 0x2e,
+ 0x3c, 0x91, 0x3d, 0x6e, 0x53, 0xcf, 0x08, 0xe9,
+ 0x0a, 0x4b, 0xc9, 0x7e, 0x99, 0x00, 0x22, 0x00,
+ 0x0b, 0x51, 0xd3, 0x38, 0xfe, 0xaa, 0xda, 0xc6,
+ 0x68, 0x84, 0x39, 0xe7, 0xb1, 0x03, 0x22, 0x5e,
+ 0xc4, 0xd3, 0xf1, 0x0c, 0xec, 0x35, 0x5d, 0x50,
+ 0xa3, 0x9d, 0xab, 0xa1, 0x7b, 0x61, 0x51, 0x8f,
+ 0x4e
+};
+
+const unsigned char x509_0_tpm_es256[1476] = {
+ 0x30, 0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x30,
+ 0xcd, 0xf2, 0x7e, 0x81, 0xc0, 0x43, 0x85, 0xa2,
+ 0xd7, 0x29, 0xef, 0xf7, 0x9f, 0xa5, 0x2b, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x41,
+ 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53,
+ 0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44,
+ 0x2d, 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34,
+ 0x41, 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37,
+ 0x41, 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30,
+ 0x30, 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31,
+ 0x41, 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36,
+ 0x30, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x31,
+ 0x31, 0x30, 0x32, 0x31, 0x35, 0x30, 0x36, 0x35,
+ 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36,
+ 0x30, 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36,
+ 0x5a, 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+ 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+ 0x82, 0x01, 0x01, 0x00, 0xdb, 0xd5, 0x9a, 0xfc,
+ 0x09, 0xa7, 0xc4, 0xa5, 0x5f, 0xbe, 0x5f, 0xa2,
+ 0xeb, 0xd6, 0x8e, 0xed, 0xc5, 0x67, 0xa6, 0xa7,
+ 0xd9, 0xb2, 0x46, 0xc6, 0xe0, 0xae, 0x0c, 0x02,
+ 0x25, 0x0a, 0xf2, 0xc5, 0x96, 0xdc, 0xb7, 0x0e,
+ 0xb9, 0x86, 0xd3, 0x51, 0xbb, 0x63, 0xf0, 0x4f,
+ 0x8a, 0x5e, 0xd7, 0xf7, 0xff, 0xbb, 0x29, 0xbd,
+ 0x58, 0xcf, 0x75, 0x02, 0x39, 0xcb, 0x80, 0xf1,
+ 0xd4, 0xb6, 0x75, 0x67, 0x2f, 0x27, 0x4d, 0x0c,
+ 0xcc, 0x18, 0x59, 0x87, 0xfa, 0x51, 0xd1, 0x80,
+ 0xb5, 0x1a, 0xac, 0xac, 0x29, 0x51, 0xcf, 0x27,
+ 0xaa, 0x74, 0xac, 0x3e, 0x59, 0x56, 0x67, 0xe4,
+ 0x42, 0xe8, 0x30, 0x35, 0xb2, 0xf6, 0x27, 0x91,
+ 0x62, 0x60, 0x42, 0x42, 0x12, 0xde, 0xfe, 0xdd,
+ 0xee, 0xe8, 0xa8, 0x82, 0xf9, 0xb1, 0x08, 0xd5,
+ 0x8d, 0x57, 0x9a, 0x29, 0xb9, 0xb4, 0xe9, 0x19,
+ 0x1e, 0x33, 0x7d, 0x37, 0xa0, 0xce, 0x2e, 0x53,
+ 0x13, 0x39, 0xb6, 0x12, 0x61, 0x63, 0xbf, 0xd3,
+ 0x42, 0xeb, 0x6f, 0xed, 0xc1, 0x8e, 0x26, 0xba,
+ 0x7d, 0x8b, 0x37, 0x7c, 0xbb, 0x42, 0x1e, 0x56,
+ 0x76, 0xda, 0xdb, 0x35, 0x6b, 0x80, 0xe1, 0x8e,
+ 0x00, 0xac, 0xd2, 0xfc, 0x22, 0x96, 0x14, 0x0c,
+ 0xf4, 0xe4, 0xc5, 0xad, 0x14, 0xb7, 0x4d, 0x46,
+ 0x63, 0x30, 0x79, 0x3a, 0x7c, 0x33, 0xb5, 0xe5,
+ 0x2e, 0xbb, 0x5f, 0xca, 0xf2, 0x75, 0xe3, 0x4e,
+ 0x99, 0x64, 0x1b, 0x26, 0x99, 0x60, 0x1a, 0x79,
+ 0xcc, 0x30, 0x2c, 0xb3, 0x4c, 0x59, 0xf7, 0x77,
+ 0x59, 0xd5, 0x90, 0x70, 0x21, 0x79, 0x8c, 0x1f,
+ 0x79, 0x0a, 0x12, 0x8b, 0x3b, 0x37, 0x2d, 0x97,
+ 0x39, 0x89, 0x92, 0x0c, 0x44, 0x7c, 0xe9, 0x9f,
+ 0xce, 0x6d, 0xad, 0xc5, 0xae, 0xea, 0x8e, 0x50,
+ 0x22, 0x37, 0xe0, 0xd1, 0x9e, 0xd6, 0xe6, 0xa8,
+ 0xcc, 0x21, 0xfb, 0xff, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xa3, 0x82, 0x01, 0xf3, 0x30, 0x82, 0x01,
+ 0xef, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+ 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07,
+ 0x80, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30,
+ 0x6d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01,
+ 0xff, 0x04, 0x63, 0x30, 0x61, 0x30, 0x5f, 0x06,
+ 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
+ 0x15, 0x1f, 0x30, 0x52, 0x30, 0x50, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02,
+ 0x30, 0x44, 0x1e, 0x42, 0x00, 0x54, 0x00, 0x43,
+ 0x00, 0x50, 0x00, 0x41, 0x00, 0x20, 0x00, 0x20,
+ 0x00, 0x54, 0x00, 0x72, 0x00, 0x75, 0x00, 0x73,
+ 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20,
+ 0x00, 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61,
+ 0x00, 0x74, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72,
+ 0x00, 0x6d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49,
+ 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74,
+ 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x30, 0x10,
+ 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30,
+ 0x07, 0x06, 0x05, 0x67, 0x81, 0x05, 0x08, 0x03,
+ 0x30, 0x59, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01,
+ 0x01, 0xff, 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b,
+ 0x30, 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05,
+ 0x67, 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69,
+ 0x64, 0x3a, 0x35, 0x33, 0x35, 0x34, 0x34, 0x44,
+ 0x32, 0x30, 0x31, 0x17, 0x30, 0x15, 0x06, 0x05,
+ 0x67, 0x81, 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53,
+ 0x54, 0x33, 0x33, 0x48, 0x54, 0x50, 0x48, 0x41,
+ 0x48, 0x42, 0x34, 0x31, 0x16, 0x30, 0x14, 0x06,
+ 0x05, 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b,
+ 0x69, 0x64, 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30,
+ 0x30, 0x30, 0x34, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0x45, 0x1a, 0xec, 0xfc, 0x91, 0x70, 0xf8, 0x83,
+ 0x8b, 0x9c, 0x47, 0x2f, 0x0b, 0x9f, 0x07, 0xf3,
+ 0x2f, 0x7c, 0xa2, 0x8a, 0x30, 0x1d, 0x06, 0x03,
+ 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x55,
+ 0xa6, 0xee, 0xe3, 0x28, 0xdd, 0x40, 0x7f, 0x21,
+ 0xd2, 0x7b, 0x8c, 0x69, 0x2f, 0x8c, 0x08, 0x29,
+ 0xbc, 0x95, 0xb8, 0x30, 0x81, 0xb2, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
+ 0x04, 0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x81,
+ 0x9f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x30, 0x02, 0x86, 0x81, 0x92, 0x68, 0x74,
+ 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x7a, 0x63,
+ 0x73, 0x70, 0x72, 0x6f, 0x64, 0x65, 0x75, 0x73,
+ 0x61, 0x69, 0x6b, 0x70, 0x75, 0x62, 0x6c, 0x69,
+ 0x73, 0x68, 0x2e, 0x62, 0x6c, 0x6f, 0x62, 0x2e,
+ 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x77, 0x69, 0x6e,
+ 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x6e, 0x65, 0x74,
+ 0x2f, 0x65, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d,
+ 0x2d, 0x6b, 0x65, 0x79, 0x69, 0x64, 0x2d, 0x31,
+ 0x61, 0x64, 0x62, 0x39, 0x39, 0x34, 0x61, 0x62,
+ 0x35, 0x38, 0x62, 0x65, 0x35, 0x37, 0x61, 0x30,
+ 0x63, 0x63, 0x39, 0x62, 0x39, 0x30, 0x30, 0x65,
+ 0x37, 0x38, 0x35, 0x31, 0x65, 0x31, 0x61, 0x34,
+ 0x33, 0x63, 0x30, 0x38, 0x36, 0x36, 0x30, 0x2f,
+ 0x62, 0x36, 0x63, 0x30, 0x64, 0x39, 0x38, 0x64,
+ 0x2d, 0x35, 0x37, 0x38, 0x61, 0x2d, 0x34, 0x62,
+ 0x66, 0x62, 0x2d, 0x61, 0x32, 0x64, 0x33, 0x2d,
+ 0x65, 0x64, 0x66, 0x65, 0x35, 0x66, 0x38, 0x32,
+ 0x30, 0x36, 0x30, 0x31, 0x2e, 0x63, 0x65, 0x72,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+ 0x82, 0x02, 0x01, 0x00, 0x2a, 0x08, 0x30, 0x1f,
+ 0xfd, 0x8f, 0x80, 0x9b, 0x4b, 0x37, 0x82, 0x61,
+ 0x86, 0x36, 0x57, 0x90, 0xb5, 0x1d, 0x1f, 0xa3,
+ 0xae, 0x68, 0xac, 0xa7, 0x96, 0x6a, 0x25, 0x5e,
+ 0xc5, 0x82, 0x7c, 0x36, 0x64, 0x58, 0x11, 0xcb,
+ 0xa5, 0xee, 0xbf, 0xc4, 0xdb, 0xa0, 0xc7, 0x82,
+ 0x3b, 0xa3, 0x85, 0x9b, 0xc4, 0xee, 0x07, 0x36,
+ 0xd7, 0xc7, 0xb6, 0x23, 0xed, 0xc2, 0x73, 0xab,
+ 0xbe, 0xbe, 0xee, 0x63, 0x17, 0xf9, 0xd7, 0x7a,
+ 0x23, 0x7b, 0xf8, 0x09, 0x7a, 0xaa, 0x7f, 0x67,
+ 0xc3, 0x04, 0x84, 0x71, 0x9b, 0x06, 0x9c, 0x07,
+ 0x42, 0x4b, 0x65, 0x41, 0x56, 0x58, 0x14, 0x92,
+ 0xb0, 0xb9, 0xaf, 0xa1, 0x39, 0xd4, 0x08, 0x2d,
+ 0x71, 0xd5, 0x6c, 0x56, 0xb9, 0x2b, 0x1e, 0xf3,
+ 0x93, 0xa5, 0xe9, 0xb2, 0x9b, 0x4d, 0x05, 0x2b,
+ 0xbc, 0xd2, 0x20, 0x57, 0x3b, 0xa4, 0x01, 0x68,
+ 0x8c, 0x23, 0x20, 0x7d, 0xbb, 0x71, 0xe4, 0x2a,
+ 0x24, 0xba, 0x75, 0x0c, 0x89, 0x54, 0x22, 0xeb,
+ 0x0e, 0xb2, 0xf4, 0xc2, 0x1f, 0x02, 0xb7, 0xe3,
+ 0x06, 0x41, 0x15, 0x6b, 0xf3, 0xc8, 0x2d, 0x5b,
+ 0xc2, 0x21, 0x82, 0x3e, 0xe8, 0x95, 0x40, 0x39,
+ 0x9e, 0x91, 0x68, 0x33, 0x0c, 0x3d, 0x45, 0xef,
+ 0x99, 0x79, 0xe6, 0x32, 0xc9, 0x00, 0x84, 0x36,
+ 0xfb, 0x0a, 0x8d, 0x41, 0x1c, 0x32, 0x64, 0x06,
+ 0x9e, 0x0f, 0xb5, 0x04, 0xcc, 0x08, 0xb1, 0xb6,
+ 0x2b, 0xcf, 0x36, 0x0f, 0x73, 0x14, 0x8e, 0x25,
+ 0x44, 0xb3, 0x0c, 0x34, 0x14, 0x96, 0x0c, 0x8a,
+ 0x65, 0xa1, 0xde, 0x8e, 0xc8, 0x9d, 0xbe, 0x66,
+ 0xdf, 0x06, 0x91, 0xca, 0x15, 0x0f, 0x92, 0xd5,
+ 0x2a, 0x0b, 0xdc, 0x4c, 0x6a, 0xf3, 0x16, 0x4a,
+ 0x3e, 0xb9, 0x76, 0xbc, 0xfe, 0x62, 0xd4, 0xa8,
+ 0xcd, 0x94, 0x78, 0x0d, 0xdd, 0x94, 0xfd, 0x5e,
+ 0x63, 0x57, 0x27, 0x05, 0x9c, 0xd0, 0x80, 0x91,
+ 0x91, 0x79, 0xe8, 0x5e, 0x18, 0x64, 0x22, 0xe4,
+ 0x2c, 0x13, 0x65, 0xa4, 0x51, 0x5a, 0x1e, 0x3b,
+ 0x71, 0x2e, 0x70, 0x9f, 0xc4, 0xa5, 0x20, 0xcd,
+ 0xef, 0xd8, 0x3f, 0xa4, 0xf5, 0x89, 0x8a, 0xa5,
+ 0x4f, 0x76, 0x2d, 0x49, 0x56, 0x00, 0x8d, 0xde,
+ 0x40, 0xba, 0x24, 0x46, 0x51, 0x38, 0xad, 0xdb,
+ 0xc4, 0x04, 0xf4, 0x6e, 0xc0, 0x29, 0x48, 0x07,
+ 0x6a, 0x1b, 0x26, 0x32, 0x0a, 0xfb, 0xea, 0x71,
+ 0x2a, 0x11, 0xfc, 0x98, 0x7c, 0x44, 0x87, 0xbc,
+ 0x06, 0x3a, 0x4d, 0xbd, 0x91, 0x63, 0x4f, 0x26,
+ 0x48, 0x54, 0x47, 0x1b, 0xbd, 0xf0, 0xf1, 0x56,
+ 0x05, 0xc5, 0x0f, 0x8f, 0x20, 0xa5, 0xcc, 0xfb,
+ 0x76, 0xb0, 0xbd, 0x83, 0xde, 0x7f, 0x39, 0x4f,
+ 0xcf, 0x61, 0x74, 0x52, 0xa7, 0x1d, 0xf6, 0xb5,
+ 0x5e, 0x4a, 0x82, 0x20, 0xc1, 0x94, 0xaa, 0x2c,
+ 0x33, 0xd6, 0x0a, 0xf9, 0x8f, 0x92, 0xc6, 0x29,
+ 0x80, 0xf5, 0xa2, 0xb1, 0xff, 0xb6, 0x2b, 0xaa,
+ 0x04, 0x00, 0x72, 0xb4, 0x12, 0xbb, 0xb1, 0xf1,
+ 0x3c, 0x88, 0xa3, 0xab, 0x49, 0x17, 0x90, 0x80,
+ 0x59, 0xa2, 0x96, 0x41, 0x69, 0x74, 0x33, 0x8a,
+ 0x28, 0x33, 0x7e, 0xb3, 0x19, 0x92, 0x28, 0xc1,
+ 0xf0, 0xd1, 0x82, 0xd5, 0x42, 0xff, 0xe7, 0xa5,
+ 0x3f, 0x1e, 0xb6, 0x4a, 0x23, 0xcc, 0x6a, 0x7f,
+ 0x15, 0x15, 0x52, 0x25, 0xb1, 0xca, 0x21, 0x95,
+ 0x11, 0x53, 0x3e, 0x1f, 0x50, 0x33, 0x12, 0x7a,
+ 0x62, 0xce, 0xcc, 0x71, 0xc2, 0x5f, 0x34, 0x47,
+ 0xc6, 0x7c, 0x71, 0xfa, 0xa0, 0x54, 0x00, 0xb2,
+ 0xdf, 0xc5, 0x54, 0xac, 0x6c, 0x53, 0xef, 0x64,
+ 0x6b, 0x08, 0x82, 0xd8, 0x16, 0x1e, 0xca, 0x40,
+ 0xf3, 0x1f, 0xdf, 0x56, 0x63, 0x10, 0xbc, 0xd7,
+ 0xa0, 0xeb, 0xee, 0xd1, 0x95, 0xe5, 0xef, 0xf1,
+ 0x6a, 0x83, 0x2d, 0x5a
+};
+
+const unsigned char x509_1_tpm_es256[1775] = {
+ 0x30, 0x82, 0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33,
+ 0x00, 0x00, 0x05, 0x23, 0xbf, 0xe8, 0xa1, 0x1a,
+ 0x2a, 0x68, 0xbd, 0x09, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x23, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+ 0x00, 0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68,
+ 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10,
+ 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
+ 0x07, 0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64,
+ 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f,
+ 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72,
+ 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f,
+ 0x73, 0x6f, 0x66, 0x74, 0x20, 0x54, 0x50, 0x4d,
+ 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65,
+ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+ 0x69, 0x74, 0x79, 0x20, 0x32, 0x30, 0x31, 0x34,
+ 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x36,
+ 0x30, 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36,
+ 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30,
+ 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 0x5a,
+ 0x30, 0x41, 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x13, 0x36, 0x45, 0x55, 0x53,
+ 0x2d, 0x53, 0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59,
+ 0x49, 0x44, 0x2d, 0x31, 0x41, 0x44, 0x42, 0x39,
+ 0x39, 0x34, 0x41, 0x42, 0x35, 0x38, 0x42, 0x45,
+ 0x35, 0x37, 0x41, 0x30, 0x43, 0x43, 0x39, 0x42,
+ 0x39, 0x30, 0x30, 0x45, 0x37, 0x38, 0x35, 0x31,
+ 0x45, 0x31, 0x41, 0x34, 0x33, 0x43, 0x30, 0x38,
+ 0x36, 0x36, 0x30, 0x30, 0x82, 0x02, 0x22, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+ 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+ 0x82, 0x02, 0x01, 0x00, 0xdb, 0x03, 0x34, 0x82,
+ 0xfa, 0x81, 0x1c, 0x84, 0x0b, 0xa0, 0x0e, 0x60,
+ 0xd8, 0x9d, 0x84, 0xf4, 0x81, 0xc4, 0xe9, 0xff,
+ 0xcf, 0xe9, 0xa3, 0x57, 0x53, 0x60, 0xa8, 0x19,
+ 0xce, 0xbe, 0xe1, 0x97, 0xee, 0x5d, 0x8c, 0x9f,
+ 0xe4, 0xbd, 0xef, 0xbd, 0x94, 0x14, 0xe4, 0x74,
+ 0x41, 0x02, 0xe9, 0x03, 0x19, 0x9f, 0xdd, 0x48,
+ 0x2d, 0xbd, 0xca, 0x26, 0x47, 0x2c, 0x01, 0x31,
+ 0x5f, 0x34, 0xef, 0x59, 0x35, 0x48, 0x36, 0x3d,
+ 0x1e, 0xdf, 0xd8, 0x13, 0xf0, 0xd0, 0x67, 0xc1,
+ 0xb0, 0x47, 0x67, 0xa2, 0xd6, 0x62, 0xc8, 0xe1,
+ 0x00, 0x36, 0x8b, 0x45, 0xf6, 0x3b, 0x96, 0x60,
+ 0xa0, 0x45, 0x26, 0xcb, 0xc7, 0x0b, 0x5b, 0x97,
+ 0xd1, 0xaf, 0x54, 0x25, 0x7a, 0x67, 0xe4, 0x2a,
+ 0xd8, 0x9d, 0x53, 0x05, 0xbd, 0x12, 0xac, 0xa2,
+ 0x8e, 0x95, 0xb4, 0x2a, 0xca, 0x89, 0x93, 0x64,
+ 0x97, 0x25, 0xdc, 0x1f, 0xa9, 0xe0, 0x55, 0x07,
+ 0x38, 0x1d, 0xee, 0x02, 0x90, 0x22, 0xf5, 0xad,
+ 0x4e, 0x5c, 0xf8, 0xc5, 0x1f, 0x9e, 0x84, 0x7e,
+ 0x13, 0x47, 0x52, 0xa2, 0x36, 0xf9, 0xf6, 0xbf,
+ 0x76, 0x9e, 0x0f, 0xdd, 0x14, 0x99, 0xb9, 0xd8,
+ 0x5a, 0x42, 0x3d, 0xd8, 0xbf, 0xdd, 0xb4, 0x9b,
+ 0xbf, 0x6a, 0x9f, 0x89, 0x13, 0x75, 0xaf, 0x96,
+ 0xd2, 0x72, 0xdf, 0xb3, 0x80, 0x6f, 0x84, 0x1a,
+ 0x9d, 0x06, 0x55, 0x09, 0x29, 0xea, 0xa7, 0x05,
+ 0x31, 0xec, 0x47, 0x3a, 0xcf, 0x3f, 0x9c, 0x2c,
+ 0xbd, 0xd0, 0x7d, 0xe4, 0x75, 0x5b, 0x33, 0xbe,
+ 0x12, 0x86, 0x09, 0xcf, 0x66, 0x9a, 0xeb, 0xf8,
+ 0xf8, 0x72, 0x91, 0x88, 0x4a, 0x5e, 0x89, 0x62,
+ 0x6a, 0x94, 0xdc, 0x48, 0x37, 0x13, 0xd8, 0x91,
+ 0x02, 0xe3, 0x42, 0x41, 0x7c, 0x2f, 0xe3, 0xb6,
+ 0x0f, 0xb4, 0x96, 0x06, 0x80, 0xca, 0x28, 0x01,
+ 0x6f, 0x4b, 0xcd, 0x28, 0xd4, 0x2c, 0x94, 0x7e,
+ 0x40, 0x7e, 0xdf, 0x01, 0xe5, 0xf2, 0x33, 0xd4,
+ 0xda, 0xf4, 0x1a, 0x17, 0xf7, 0x5d, 0xcb, 0x66,
+ 0x2c, 0x2a, 0xeb, 0xe1, 0xb1, 0x4a, 0xc3, 0x85,
+ 0x63, 0xb2, 0xac, 0xd0, 0x3f, 0x1a, 0x8d, 0xa5,
+ 0x0c, 0xee, 0x4f, 0xde, 0x74, 0x9c, 0xe0, 0x5a,
+ 0x10, 0xc7, 0xb8, 0xe4, 0xec, 0xe7, 0x73, 0xa6,
+ 0x41, 0x42, 0x37, 0xe1, 0xdf, 0xb9, 0xc7, 0xb5,
+ 0x14, 0xa8, 0x80, 0x95, 0xa0, 0x12, 0x67, 0x99,
+ 0xf5, 0xba, 0x25, 0x0a, 0x74, 0x86, 0x71, 0x9c,
+ 0x7f, 0x59, 0x97, 0xd2, 0x3f, 0x10, 0xfe, 0x6a,
+ 0xb9, 0xe4, 0x47, 0x36, 0xfb, 0x0f, 0x50, 0xee,
+ 0xfc, 0x87, 0x99, 0x7e, 0x36, 0x64, 0x1b, 0xc7,
+ 0x13, 0xb3, 0x33, 0x18, 0x71, 0xa4, 0xc3, 0xb0,
+ 0xfc, 0x45, 0x37, 0x11, 0x40, 0xb3, 0xde, 0x2c,
+ 0x9f, 0x0a, 0xcd, 0xaf, 0x5e, 0xfb, 0xd5, 0x9c,
+ 0xea, 0xd7, 0x24, 0x19, 0x3a, 0x92, 0x80, 0xa5,
+ 0x63, 0xc5, 0x3e, 0xdd, 0x51, 0xd0, 0x9f, 0xb8,
+ 0x5e, 0xd5, 0xf1, 0xfe, 0xa5, 0x93, 0xfb, 0x7f,
+ 0xd9, 0xb8, 0xb7, 0x0e, 0x0d, 0x12, 0x71, 0xf0,
+ 0x52, 0x9d, 0xe9, 0xd0, 0xd2, 0x8b, 0x38, 0x8b,
+ 0x85, 0x83, 0x98, 0x24, 0x88, 0xe8, 0x42, 0x30,
+ 0x83, 0x12, 0xef, 0x09, 0x96, 0x2f, 0x21, 0x81,
+ 0x05, 0x30, 0x0c, 0xbb, 0xba, 0x21, 0x39, 0x16,
+ 0x12, 0xe8, 0x4b, 0x7b, 0x7a, 0x66, 0xb8, 0x22,
+ 0x2c, 0x71, 0xaf, 0x59, 0xa1, 0xfc, 0x61, 0xf1,
+ 0xb4, 0x5e, 0xfc, 0x43, 0x19, 0x45, 0x6e, 0xa3,
+ 0x45, 0xe4, 0xcb, 0x66, 0x5f, 0xe0, 0x57, 0xf6,
+ 0x0a, 0x30, 0xa3, 0xd6, 0x51, 0x24, 0xc9, 0x07,
+ 0x55, 0x82, 0x4a, 0x66, 0x0e, 0x9d, 0xb2, 0x2f,
+ 0x84, 0x56, 0x6c, 0x3e, 0x71, 0xef, 0x9b, 0x35,
+ 0x4d, 0x72, 0xdc, 0x46, 0x2a, 0xe3, 0x7b, 0x13,
+ 0x20, 0xbf, 0xab, 0x77, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xa3, 0x82, 0x01, 0x8e, 0x30, 0x82, 0x01,
+ 0x8a, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+ 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
+ 0x84, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x25,
+ 0x04, 0x14, 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06,
+ 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x24, 0x06,
+ 0x05, 0x67, 0x81, 0x05, 0x08, 0x03, 0x30, 0x16,
+ 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x0f, 0x30,
+ 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01,
+ 0x04, 0x01, 0x82, 0x37, 0x15, 0x1f, 0x30, 0x12,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+ 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
+ 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+ 0x0e, 0x04, 0x16, 0x04, 0x14, 0x45, 0x1a, 0xec,
+ 0xfc, 0x91, 0x70, 0xf8, 0x83, 0x8b, 0x9c, 0x47,
+ 0x2f, 0x0b, 0x9f, 0x07, 0xf3, 0x2f, 0x7c, 0xa2,
+ 0x8a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+ 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7a, 0x8c,
+ 0x0a, 0xce, 0x2f, 0x48, 0x62, 0x17, 0xe2, 0x94,
+ 0xd1, 0xae, 0x55, 0xc1, 0x52, 0xec, 0x71, 0x74,
+ 0xa4, 0x56, 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d,
+ 0x1f, 0x04, 0x69, 0x30, 0x67, 0x30, 0x65, 0xa0,
+ 0x63, 0xa0, 0x61, 0x86, 0x5f, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
+ 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,
+ 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b,
+ 0x69, 0x6f, 0x70, 0x73, 0x2f, 0x63, 0x72, 0x6c,
+ 0x2f, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
+ 0x66, 0x74, 0x25, 0x32, 0x30, 0x54, 0x50, 0x4d,
+ 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25,
+ 0x32, 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x25, 0x32, 0x30,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x34,
+ 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x7d, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
+ 0x04, 0x71, 0x30, 0x6f, 0x30, 0x6d, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02,
+ 0x86, 0x61, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63,
+ 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x6f, 0x70,
+ 0x73, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f,
+ 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,
+ 0x74, 0x25, 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25,
+ 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32,
+ 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41,
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+ 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e,
+ 0x63, 0x72, 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+ 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x48,
+ 0x24, 0x32, 0xe8, 0xd6, 0x38, 0xda, 0x65, 0xec,
+ 0x1b, 0x18, 0x8e, 0x37, 0x07, 0xd5, 0x18, 0x5a,
+ 0xc8, 0xb9, 0xbb, 0x24, 0x8a, 0x4d, 0xa1, 0x3c,
+ 0x9e, 0x46, 0x76, 0xcf, 0xa5, 0xdf, 0xd7, 0x61,
+ 0xba, 0x05, 0x89, 0x3c, 0x13, 0xc2, 0x1f, 0x71,
+ 0xe3, 0xec, 0x5d, 0x54, 0x9e, 0xd9, 0x01, 0x5a,
+ 0x10, 0x3b, 0x17, 0x75, 0xde, 0xa1, 0x45, 0xbf,
+ 0x1d, 0x1b, 0x41, 0x21, 0x42, 0x68, 0x22, 0x6b,
+ 0xbb, 0xcb, 0x11, 0x04, 0xd2, 0xae, 0x86, 0xcf,
+ 0x73, 0x5a, 0xf2, 0x80, 0x18, 0x00, 0xf0, 0xd6,
+ 0x6c, 0x5a, 0x1e, 0xb3, 0x4d, 0x30, 0x02, 0x4a,
+ 0x6a, 0x03, 0x36, 0x42, 0xde, 0xb2, 0x52, 0x55,
+ 0xff, 0x71, 0xeb, 0x7b, 0x8b, 0x55, 0x6c, 0xdf,
+ 0x05, 0x35, 0x47, 0x70, 0x53, 0xfb, 0x6c, 0xba,
+ 0x06, 0xb2, 0x61, 0x86, 0xdc, 0x2a, 0x64, 0x81,
+ 0x24, 0x79, 0x46, 0x73, 0x04, 0x55, 0x59, 0xed,
+ 0xd6, 0x06, 0x61, 0x15, 0xf9, 0x8d, 0x78, 0x39,
+ 0x7b, 0x84, 0x7a, 0x40, 0x45, 0x13, 0x1a, 0x91,
+ 0x71, 0x8f, 0xd1, 0x4f, 0x78, 0x10, 0x68, 0x9b,
+ 0x15, 0x79, 0x3f, 0x79, 0x2d, 0x9b, 0xc7, 0x5d,
+ 0xa3, 0xcf, 0xa9, 0x14, 0xb0, 0xc4, 0xdb, 0xa9,
+ 0x45, 0x6a, 0x6e, 0x60, 0x45, 0x0b, 0x14, 0x25,
+ 0xc7, 0x74, 0xd0, 0x36, 0xaf, 0xc5, 0xbd, 0x4f,
+ 0x7b, 0xc0, 0x04, 0x43, 0x85, 0xbb, 0x06, 0x36,
+ 0x77, 0x26, 0x02, 0x23, 0x0b, 0xf8, 0x57, 0x8f,
+ 0x1f, 0x27, 0x30, 0x95, 0xff, 0x83, 0x23, 0x2b,
+ 0x49, 0x33, 0x43, 0x62, 0x87, 0x5d, 0x27, 0x12,
+ 0x1a, 0x68, 0x7b, 0xba, 0x2d, 0xf6, 0xed, 0x2c,
+ 0x26, 0xb5, 0xbb, 0xe2, 0x6f, 0xc2, 0x61, 0x17,
+ 0xfc, 0x72, 0x14, 0x57, 0x2c, 0x2c, 0x5a, 0x92,
+ 0x13, 0x41, 0xc4, 0x7e, 0xb5, 0x64, 0x5b, 0x86,
+ 0x57, 0x13, 0x14, 0xff, 0xf5, 0x04, 0xb9, 0x3d,
+ 0x2d, 0xc3, 0xe9, 0x75, 0x1f, 0x68, 0x0b, 0xb5,
+ 0x76, 0xe1, 0x7d, 0xe3, 0xb0, 0x14, 0xa8, 0x45,
+ 0x05, 0x98, 0x81, 0x32, 0xc1, 0xf5, 0x49, 0x4d,
+ 0x58, 0xa4, 0xee, 0xd8, 0x84, 0xba, 0x65, 0x07,
+ 0x8d, 0xf7, 0x9a, 0xff, 0x7d, 0xa5, 0xbc, 0x9a,
+ 0xed, 0x4a, 0x5d, 0xa4, 0x97, 0x4b, 0x4d, 0x31,
+ 0x90, 0xb5, 0x7d, 0x28, 0x77, 0x25, 0x88, 0x1c,
+ 0xbf, 0x78, 0x22, 0xb2, 0xb5, 0x5c, 0x9a, 0xc9,
+ 0x63, 0x17, 0x96, 0xe9, 0xc2, 0x52, 0x30, 0xb8,
+ 0x9b, 0x37, 0x69, 0x1a, 0x6a, 0x66, 0x76, 0x18,
+ 0xac, 0xc0, 0x48, 0xee, 0x46, 0x5b, 0xbe, 0x6a,
+ 0xd5, 0x72, 0x07, 0xdc, 0x7d, 0x05, 0xbe, 0x76,
+ 0x7d, 0xa5, 0x5e, 0x53, 0xb5, 0x47, 0x80, 0x58,
+ 0xf0, 0xaf, 0x6f, 0x4e, 0xc0, 0xf1, 0x1e, 0x37,
+ 0x64, 0x15, 0x42, 0x96, 0x18, 0x3a, 0x89, 0xc8,
+ 0x14, 0x48, 0x89, 0x5c, 0x12, 0x88, 0x98, 0x0b,
+ 0x7b, 0x4e, 0xce, 0x1c, 0xda, 0xd5, 0xa4, 0xd3,
+ 0x32, 0x32, 0x74, 0x5b, 0xcc, 0xfd, 0x2b, 0x02,
+ 0xfb, 0xae, 0xd0, 0x5a, 0x4c, 0xc9, 0xc1, 0x35,
+ 0x19, 0x90, 0x5f, 0xca, 0x14, 0xeb, 0x4c, 0x17,
+ 0xd7, 0xe3, 0xe2, 0x5d, 0xb4, 0x49, 0xaa, 0xf0,
+ 0x50, 0x87, 0xc3, 0x20, 0x00, 0xda, 0xe9, 0x04,
+ 0x80, 0x64, 0xac, 0x9f, 0xcd, 0x26, 0x41, 0x48,
+ 0xe8, 0x4c, 0x46, 0xcc, 0x5b, 0xd7, 0xca, 0x4c,
+ 0x1b, 0x43, 0x43, 0x1e, 0xbd, 0x94, 0xe7, 0xa7,
+ 0xa6, 0x86, 0xe5, 0xd1, 0x78, 0x29, 0xa2, 0x40,
+ 0xc5, 0xc5, 0x47, 0xb6, 0x6d, 0x53, 0xde, 0xac,
+ 0x97, 0x74, 0x24, 0x57, 0xcc, 0x05, 0x93, 0xfd,
+ 0x52, 0x35, 0x29, 0xd5, 0xe0, 0xfa, 0x23, 0x0d,
+ 0xd7, 0xaa, 0x8b, 0x07, 0x4b, 0xf6, 0x64, 0xc7,
+ 0xad, 0x3c, 0xa1, 0xb5, 0xc5, 0x70, 0xaf, 0x46,
+ 0xfe, 0x9a, 0x82, 0x4d, 0x75, 0xb8, 0x6d
+};
+
+
+/*
+ * Security Key By Yubico
+ * 5.1.X
+ * f8a011f3-8c0a-4d15-8006-17111f9edc7d
+ */
+const unsigned char aaguid[16] = {
+ 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15,
+ 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d,
+};
+
+/*
+ * Windows Hello by Microsoft
+ */
+const unsigned char aaguid_tpm[16] = {
+ 0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81,
+ 0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96,
+};
+
+const char rp_id[] = "localhost";
+const char rp_name[] = "sweet home localhost";
+
+static void *
+dummy_open(const char *path)
+{
+ (void)path;
+
+ return (&fake_dev_handle);
+}
+
+static void
+dummy_close(void *handle)
+{
+ assert(handle == &fake_dev_handle);
+}
+
+static int
+dummy_read(void *handle, unsigned char *buf, size_t len, int ms)
+{
+ (void)handle;
+ (void)buf;
+ (void)len;
+ (void)ms;
+
+ abort();
+ /* NOTREACHED */
+}
+
+static int
+dummy_write(void *handle, const unsigned char *buf, size_t len)
+{
+ (void)handle;
+ (void)buf;
+ (void)len;
+
+ abort();
+ /* NOTREACHED */
+}
+
+static fido_cred_t *
+alloc_cred(void)
+{
+ fido_cred_t *c;
+
+ c = fido_cred_new();
+ assert(c != NULL);
+
+ return (c);
+}
+
+static void
+free_cred(fido_cred_t *c)
+{
+ fido_cred_free(&c);
+ assert(c == NULL);
+}
+
+static fido_dev_t *
+alloc_dev(void)
+{
+ fido_dev_t *d;
+
+ d = fido_dev_new();
+ assert(d != NULL);
+
+ return (d);
+}
+
+static void
+free_dev(fido_dev_t *d)
+{
+ fido_dev_free(&d);
+ assert(d == NULL);
+}
+
+static void
+empty_cred(void)
+{
+ fido_cred_t *c;
+ fido_dev_t *d;
+ fido_dev_io_t io_f;
+
+ c = alloc_cred();
+ assert(fido_cred_authdata_len(c) == 0);
+ assert(fido_cred_authdata_ptr(c) == NULL);
+ assert(fido_cred_authdata_raw_len(c) == 0);
+ assert(fido_cred_authdata_raw_ptr(c) == NULL);
+ assert(fido_cred_clientdata_hash_len(c) == 0);
+ assert(fido_cred_clientdata_hash_ptr(c) == NULL);
+ assert(fido_cred_flags(c) == 0);
+ assert(fido_cred_fmt(c) == NULL);
+ assert(fido_cred_id_len(c) == 0);
+ assert(fido_cred_id_ptr(c) == NULL);
+ assert(fido_cred_prot(c) == 0);
+ assert(fido_cred_pubkey_len(c) == 0);
+ assert(fido_cred_pubkey_ptr(c) == NULL);
+ assert(fido_cred_rp_id(c) == NULL);
+ assert(fido_cred_rp_name(c) == NULL);
+ assert(fido_cred_sig_len(c) == 0);
+ assert(fido_cred_sig_ptr(c) == NULL);
+ assert(fido_cred_x5c_len(c) == 0);
+ assert(fido_cred_x5c_ptr(c) == NULL);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+
+ memset(&io_f, 0, sizeof(io_f));
+
+ io_f.open = dummy_open;
+ io_f.close = dummy_close;
+ io_f.read = dummy_read;
+ io_f.write = dummy_write;
+
+ d = alloc_dev();
+
+ fido_dev_force_u2f(d);
+ assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK);
+ assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_UNSUPPORTED_OPTION);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+
+ fido_dev_force_fido2(d);
+ assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK);
+ assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+
+ free_cred(c);
+ free_dev(d);
+}
+
+static void
+valid_cred(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_OK);
+ assert(fido_cred_prot(c) == 0);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_cdh(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_rp_id(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_rp_name(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, NULL) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_OK);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_authdata(void)
+{
+ fido_cred_t *c;
+ unsigned char *unset;
+
+ unset = calloc(1, sizeof(aaguid));
+ assert(unset != NULL);
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == 0);
+ assert(fido_cred_pubkey_ptr(c) == NULL);
+ assert(fido_cred_id_len(c) == 0);
+ assert(fido_cred_id_ptr(c) == NULL);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
+ free_cred(c);
+ free(unset);
+}
+
+static void
+no_x509(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_sig(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+no_fmt(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+wrong_options(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+junk_cdh(void)
+{
+ fido_cred_t *c;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(cdh));
+ assert(junk != NULL);
+ memcpy(junk, cdh, sizeof(cdh));
+ junk[0] = (unsigned char)~junk[0];
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, junk, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+ free(junk);
+}
+
+static void
+junk_fmt(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "junk") == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ free_cred(c);
+}
+
+static void
+junk_rp_id(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, "potato", rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+junk_rp_name(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, "potato") == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_OK);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+junk_authdata(void)
+{
+ fido_cred_t *c;
+ unsigned char *junk;
+ unsigned char *unset;
+
+ junk = malloc(sizeof(authdata));
+ assert(junk != NULL);
+ memcpy(junk, authdata, sizeof(authdata));
+ junk[0] = (unsigned char)~junk[0];
+
+ unset = calloc(1, sizeof(aaguid));
+ assert(unset != NULL);
+
+ c = alloc_cred();
+ assert(fido_cred_set_authdata(c, junk,
+ sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_authdata_len(c) == 0);
+ assert(fido_cred_authdata_ptr(c) == NULL);
+ assert(fido_cred_authdata_raw_len(c) == 0);
+ assert(fido_cred_authdata_raw_ptr(c) == NULL);
+ assert(fido_cred_flags(c) == 0);
+ assert(fido_cred_fmt(c) == NULL);
+ assert(fido_cred_id_len(c) == 0);
+ assert(fido_cred_id_ptr(c) == NULL);
+ assert(fido_cred_pubkey_len(c) == 0);
+ assert(fido_cred_pubkey_ptr(c) == NULL);
+ assert(fido_cred_rp_id(c) == NULL);
+ assert(fido_cred_rp_name(c) == NULL);
+ assert(fido_cred_sig_len(c) == 0);
+ assert(fido_cred_sig_ptr(c) == NULL);
+ assert(fido_cred_x5c_len(c) == 0);
+ assert(fido_cred_x5c_ptr(c) == NULL);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ free_cred(c);
+ free(junk);
+ free(unset);
+}
+
+static void
+junk_sig(void)
+{
+ fido_cred_t *c;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(sig));
+ assert(junk != NULL);
+ memcpy(junk, sig, sizeof(sig));
+ junk[0] = (unsigned char)~junk[0];
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, junk, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+ free(junk);
+}
+
+static void
+junk_x509(void)
+{
+ fido_cred_t *c;
+ unsigned char *junk;
+
+ junk = malloc(sizeof(x509));
+ assert(junk != NULL);
+ memcpy(junk, x509, sizeof(x509));
+ junk[0] = (unsigned char)~junk[0];
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, junk, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+ free(junk);
+}
+
+/* github issue #6 */
+static void
+invalid_type(void)
+{
+ fido_cred_t *c;
+ unsigned char *unset;
+
+ unset = calloc(1, sizeof(aaguid));
+ assert(unset != NULL);
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_pubkey_len(c) == 0);
+ assert(fido_cred_pubkey_ptr(c) == NULL);
+ assert(fido_cred_id_len(c) == 0);
+ assert(fido_cred_id_ptr(c) == NULL);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
+ free_cred(c);
+ free(unset);
+}
+
+/* cbor_serialize_alloc misuse */
+static void
+bad_cbor_serialize(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_authdata_len(c) == sizeof(authdata));
+ free_cred(c);
+}
+
+static void
+duplicate_keys(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata_dupkeys,
+ sizeof(authdata_dupkeys)) == FIDO_ERR_INVALID_ARGUMENT);
+ free_cred(c);
+}
+
+static void
+unsorted_keys(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata_unsorted_keys,
+ sizeof(authdata_unsorted_keys)) == FIDO_ERR_INVALID_ARGUMENT);
+ free_cred(c);
+}
+
+static void
+wrong_credprot(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
+ assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
+ assert(fido_cred_set_prot(c, FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM);
+ free_cred(c);
+}
+
+static void
+raw_authdata(void)
+{
+ fido_cred_t *c;
+ cbor_item_t *item;
+ struct cbor_load_result cbor_result;
+ const unsigned char *ptr;
+ unsigned char *cbor;
+ size_t len;
+ size_t cbor_len;
+ size_t alloclen;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert((ptr = fido_cred_authdata_ptr(c)) != NULL);
+ assert((len = fido_cred_authdata_len(c)) != 0);
+ assert((item = cbor_load(ptr, len, &cbor_result)) != NULL);
+ assert(cbor_result.read == len);
+ assert(cbor_isa_bytestring(item));
+ assert((ptr = fido_cred_authdata_raw_ptr(c)) != NULL);
+ assert((len = fido_cred_authdata_raw_len(c)) != 0);
+ assert(cbor_bytestring_length(item) == len);
+ assert(memcmp(ptr, cbor_bytestring_handle(item), len) == 0);
+ assert((len = fido_cred_authdata_len(c)) != 0);
+ assert((cbor_len = cbor_serialize_alloc(item, &cbor, &alloclen)) == len);
+ assert((ptr = cbor_bytestring_handle(item)) != NULL);
+ assert((len = cbor_bytestring_length(item)) != 0);
+ assert(fido_cred_set_authdata_raw(c, ptr, len) == FIDO_OK);
+ assert((ptr = fido_cred_authdata_ptr(c)) != NULL);
+ assert((len = fido_cred_authdata_len(c)) != 0);
+ assert(len == cbor_len);
+ assert(memcmp(cbor, ptr, len) == 0);
+ assert(cbor_len == sizeof(authdata));
+ assert(memcmp(cbor, authdata, cbor_len) == 0);
+ cbor_decref(&item);
+ free(cbor);
+ free_cred(c);
+}
+
+static void
+fmt_none(void)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "none") == FIDO_OK);
+ assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_cred_prot(c) == 0);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id));
+ assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
+ free_cred(c);
+}
+
+static void
+valid_tpm_rs256_cred(bool xfail)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK);
+ assert(fido_cred_set_clientdata(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata_tpm_rs256, sizeof(authdata_tpm_rs256)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "tpm") == FIDO_OK);
+ assert(fido_cred_set_attstmt(c, attstmt_tpm_rs256, sizeof(attstmt_tpm_rs256)) == FIDO_OK);
+ // XXX: RHEL9 has deprecated SHA-1 for signing.
+ assert(fido_cred_verify(c) == (xfail ? FIDO_ERR_INVALID_SIG : FIDO_OK));
+ assert(fido_cred_prot(c) == 0);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm_rs256));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm_rs256, sizeof(pubkey_tpm_rs256)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id_tpm_rs256));
+ assert(memcmp(fido_cred_id_ptr(c), id_tpm_rs256, sizeof(id_tpm_rs256)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid_tpm));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid_tpm, sizeof(aaguid_tpm)) == 0);
+ free_cred(c);
+}
+
+static void
+valid_tpm_es256_cred(bool xfail)
+{
+ fido_cred_t *c;
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_authdata(c, authdata_tpm_es256, sizeof(authdata_tpm_es256)) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_cred_set_fmt(c, "tpm") == FIDO_OK);
+ assert(fido_cred_set_attstmt(c, attstmt_tpm_es256, sizeof(attstmt_tpm_es256)) == FIDO_OK);
+ assert(fido_cred_x5c_list_count(c) == 2);
+ assert(fido_cred_x5c_list_len(c, 0) == sizeof(x509_0_tpm_es256));
+ assert(memcmp(fido_cred_x5c_list_ptr(c, 0), x509_0_tpm_es256, sizeof(x509_0_tpm_es256)) == 0);
+ assert(fido_cred_x5c_list_len(c, 1) == sizeof(x509_1_tpm_es256));
+ assert(memcmp(fido_cred_x5c_list_ptr(c, 1), x509_1_tpm_es256, sizeof(x509_1_tpm_es256)) == 0);
+ assert(fido_cred_x5c_list_len(c, 2) == 0);
+ assert(fido_cred_x5c_list_ptr(c, 2) == NULL);
+ // XXX: RHEL9 has deprecated SHA-1 for signing.
+ assert(fido_cred_verify(c) == (xfail ? FIDO_ERR_INVALID_SIG : FIDO_OK));
+ assert(fido_cred_prot(c) == 0);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm_es256));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm_es256, sizeof(pubkey_tpm_es256)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id_tpm_es256));
+ assert(memcmp(fido_cred_id_ptr(c), id_tpm_es256, sizeof(id_tpm_es256)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid_tpm));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid_tpm, sizeof(aaguid_tpm)) == 0);
+ free_cred(c);
+}
+
+static void
+push_kv(cbor_item_t *map, const char *key, cbor_item_t *value)
+{
+ struct cbor_pair kv;
+ cbor_item_t *tmp;
+
+ memset(&kv, 0, sizeof(kv));
+ assert(map != NULL && key != NULL && value != NULL);
+ assert((tmp = cbor_build_string(key)) != NULL);
+ /* XXX transfers ownership */
+ kv.key = cbor_move(tmp);
+ kv.value = cbor_move(value);
+ assert(cbor_map_add(map, kv));
+}
+
+static void
+attestation_object(void)
+{
+ struct cbor_load_result cbor;
+ unsigned char *attobj = NULL;
+ size_t len, alloclen = 0;
+ cbor_item_t *map;
+ fido_cred_t *c;
+
+ assert((map = cbor_new_definite_map(3)) != NULL);
+ push_kv(map, "fmt", cbor_build_string("tpm"));
+ push_kv(map, "attStmt", cbor_load(attstmt_tpm_es256,
+ sizeof(attstmt_tpm_es256), &cbor));
+ push_kv(map, "authData", cbor_load(authdata_tpm_es256,
+ sizeof(authdata_tpm_es256), &cbor));
+ assert((len = cbor_serialize_alloc(map, &attobj, &alloclen)));
+ cbor_decref(&map);
+
+ c = alloc_cred();
+ assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
+ assert(fido_cred_set_clientdata(c, cdh, sizeof(cdh)) == FIDO_OK);
+ assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
+ assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
+ assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK);
+ assert(fido_cred_set_attobj(c, attobj, len) == FIDO_OK);
+ assert(strcmp(fido_cred_fmt(c), "tpm") == 0);
+ assert(fido_cred_attstmt_len(c) == sizeof(attstmt_tpm_es256));
+ assert(memcmp(fido_cred_attstmt_ptr(c), attstmt_tpm_es256, sizeof(attstmt_tpm_es256)) == 0);
+ assert(fido_cred_authdata_len(c) == sizeof(authdata_tpm_es256));
+ assert(memcmp(fido_cred_authdata_ptr(c), authdata_tpm_es256, sizeof(authdata_tpm_es256)) == 0);
+ assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm_es256));
+ assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm_es256, sizeof(pubkey_tpm_es256)) == 0);
+ assert(fido_cred_id_len(c) == sizeof(id_tpm_es256));
+ assert(memcmp(fido_cred_id_ptr(c), id_tpm_es256, sizeof(id_tpm_es256)) == 0);
+ assert(fido_cred_aaguid_len(c) == sizeof(aaguid_tpm));
+ assert(memcmp(fido_cred_aaguid_ptr(c), aaguid_tpm, sizeof(aaguid_tpm)) == 0);
+ free_cred(c);
+ free(attobj);
+}
+
+int
+main(void)
+{
+ bool xfail = getenv("FIDO_REGRESS_RS1_XFAIL") != NULL;
+
+ fido_init(0);
+
+ empty_cred();
+ valid_cred();
+ no_cdh();
+ no_rp_id();
+ no_rp_name();
+ no_authdata();
+ no_x509();
+ no_sig();
+ no_fmt();
+ junk_cdh();
+ junk_fmt();
+ junk_rp_id();
+ junk_rp_name();
+ junk_authdata();
+ junk_x509();
+ junk_sig();
+ wrong_options();
+ invalid_type();
+ bad_cbor_serialize();
+ duplicate_keys();
+ unsorted_keys();
+ wrong_credprot();
+ raw_authdata();
+ fmt_none();
+ valid_tpm_rs256_cred(xfail);
+ valid_tpm_es256_cred(xfail);
+ attestation_object();
+
+ exit(0);
+}
diff --git a/regress/dev.c b/regress/dev.c
new file mode 100644
index 0000000..0ba552b
--- /dev/null
+++ b/regress/dev.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+
+#include "../fuzz/wiredata_fido2.h"
+
+#define REPORT_LEN (64 + 1)
+
+static uint8_t ctap_nonce[8];
+static uint8_t *wiredata_ptr;
+static size_t wiredata_len;
+static int fake_dev_handle;
+static int initialised;
+static long interval_ms;
+
+#if defined(_MSC_VER)
+static int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ if (rmtp != NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
+
+ return (0);
+}
+#endif
+
+static void *
+dummy_open(const char *path)
+{
+ (void)path;
+
+ return (&fake_dev_handle);
+}
+
+static void
+dummy_close(void *handle)
+{
+ assert(handle == &fake_dev_handle);
+}
+
+static int
+dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
+{
+ struct timespec tv;
+ size_t n;
+ long d;
+
+ assert(handle == &fake_dev_handle);
+ assert(ptr != NULL);
+ assert(len == REPORT_LEN - 1);
+
+ if (wiredata_ptr == NULL)
+ return (-1);
+
+ if (!initialised) {
+ assert(wiredata_len >= REPORT_LEN - 1);
+ memcpy(&wiredata_ptr[7], &ctap_nonce, sizeof(ctap_nonce));
+ initialised = 1;
+ }
+
+ if (ms >= 0 && ms < interval_ms)
+ d = ms;
+ else
+ d = interval_ms;
+
+ if (d) {
+ tv.tv_sec = d / 1000;
+ tv.tv_nsec = (d % 1000) * 1000000;
+ if (nanosleep(&tv, NULL) == -1)
+ err(1, "nanosleep");
+ }
+
+ if (d != interval_ms)
+ return (-1); /* timeout */
+
+ if (wiredata_len < len)
+ n = wiredata_len;
+ else
+ n = len;
+
+ memcpy(ptr, wiredata_ptr, n);
+ wiredata_ptr += n;
+ wiredata_len -= n;
+
+ return ((int)n);
+}
+
+static int
+dummy_write(void *handle, const unsigned char *ptr, size_t len)
+{
+ struct timespec tv;
+
+ assert(handle == &fake_dev_handle);
+ assert(ptr != NULL);
+ assert(len == REPORT_LEN);
+
+ if (!initialised)
+ memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce));
+
+ if (interval_ms) {
+ tv.tv_sec = interval_ms / 1000;
+ tv.tv_nsec = (interval_ms % 1000) * 1000000;
+ if (nanosleep(&tv, NULL) == -1)
+ err(1, "nanosleep");
+ }
+
+ return ((int)len);
+}
+
+static uint8_t *
+wiredata_setup(const uint8_t *data, size_t len)
+{
+ const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT };
+
+ assert(wiredata_ptr == NULL);
+ assert(SIZE_MAX - len > sizeof(ctap_init_data));
+ assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL);
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:6386)
+#endif
+ memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data));
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+ if (len)
+ memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len);
+
+ wiredata_len = sizeof(ctap_init_data) + len;
+
+ return (wiredata_ptr);
+}
+
+static void
+wiredata_clear(uint8_t **wiredata)
+{
+ free(*wiredata);
+ *wiredata = NULL;
+ wiredata_ptr = NULL;
+ wiredata_len = 0;
+ initialised = 0;
+}
+
+/* gh#56 */
+static void
+open_iff_ok(void)
+{
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX);
+ assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
+
+ fido_dev_free(&dev);
+}
+
+static void
+reopen(void)
+{
+ const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ wiredata_clear(&wiredata);
+
+ wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+}
+
+static void
+double_open(void)
+{
+ const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+}
+
+static void
+double_close(void)
+{
+ const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+}
+
+static void
+is_fido2(void)
+{
+ const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_is_fido2(dev) == true);
+ assert(fido_dev_supports_pin(dev) == true);
+ fido_dev_force_u2f(dev);
+ assert(fido_dev_is_fido2(dev) == false);
+ assert(fido_dev_supports_pin(dev) == false);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ wiredata_clear(&wiredata);
+
+ wiredata = wiredata_setup(NULL, 0);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_is_fido2(dev) == false);
+ assert(fido_dev_supports_pin(dev) == false);
+ fido_dev_force_fido2(dev);
+ assert(fido_dev_is_fido2(dev) == true);
+ assert(fido_dev_supports_pin(dev) == false);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+}
+
+static void
+has_pin(void)
+{
+ const uint8_t set_pin_data[] = {
+ WIREDATA_CTAP_CBOR_INFO,
+ WIREDATA_CTAP_CBOR_AUTHKEY,
+ WIREDATA_CTAP_CBOR_STATUS,
+ WIREDATA_CTAP_CBOR_STATUS
+ };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(set_pin_data, sizeof(set_pin_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_has_pin(dev) == false);
+ assert(fido_dev_set_pin(dev, "top secret", NULL) == FIDO_OK);
+ assert(fido_dev_has_pin(dev) == true);
+ assert(fido_dev_reset(dev) == FIDO_OK);
+ assert(fido_dev_has_pin(dev) == false);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+}
+
+static void
+timeout_rx(void)
+{
+ const uint8_t timeout_rx_data[] = {
+ WIREDATA_CTAP_CBOR_INFO,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_CBOR_STATUS
+ };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(timeout_rx_data, sizeof(timeout_rx_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK);
+ interval_ms = 1000;
+ assert(fido_dev_reset(dev) == FIDO_ERR_RX);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+ interval_ms = 0;
+}
+
+static void
+timeout_ok(void)
+{
+ const uint8_t timeout_ok_data[] = {
+ WIREDATA_CTAP_CBOR_INFO,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_KEEPALIVE,
+ WIREDATA_CTAP_CBOR_STATUS
+ };
+ uint8_t *wiredata;
+ fido_dev_t *dev = NULL;
+ fido_dev_io_t io;
+
+ memset(&io, 0, sizeof(io));
+
+ io.open = dummy_open;
+ io.close = dummy_close;
+ io.read = dummy_read;
+ io.write = dummy_write;
+
+ wiredata = wiredata_setup(timeout_ok_data, sizeof(timeout_ok_data));
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
+ assert(fido_dev_open(dev, "dummy") == FIDO_OK);
+ assert(fido_dev_set_timeout(dev, 30 * 1000) == FIDO_OK);
+ interval_ms = 1000;
+ assert(fido_dev_reset(dev) == FIDO_OK);
+ assert(fido_dev_close(dev) == FIDO_OK);
+ fido_dev_free(&dev);
+ wiredata_clear(&wiredata);
+ interval_ms = 0;
+}
+
+static void
+timeout_misc(void)
+{
+ fido_dev_t *dev;
+
+ assert((dev = fido_dev_new()) != NULL);
+ assert(fido_dev_set_timeout(dev, -2) == FIDO_ERR_INVALID_ARGUMENT);
+ assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK);
+ assert(fido_dev_set_timeout(dev, -1) == FIDO_OK);
+ fido_dev_free(&dev);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ open_iff_ok();
+ reopen();
+ double_open();
+ double_close();
+ is_fido2();
+ has_pin();
+ timeout_rx();
+ timeout_ok();
+ timeout_misc();
+
+ exit(0);
+}
diff --git a/regress/eddsa.c b/regress/eddsa.c
new file mode 100644
index 0000000..f97f97c
--- /dev/null
+++ b/regress/eddsa.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+#include
+
+#include
+#include
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static const char ecdsa[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n"
+"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char eddsa[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MCowBQYDK2VwAyEADt/RHErAxAHxH9FUmsjOhQ2ALl6Y8nE0m3zQxkEE2iM=\n"
+"-----END PUBLIC KEY-----\n";
+
+static const unsigned char eddsa_raw[] = {
+ 0x0e, 0xdf, 0xd1, 0x1c, 0x4a, 0xc0, 0xc4, 0x01,
+ 0xf1, 0x1f, 0xd1, 0x54, 0x9a, 0xc8, 0xce, 0x85,
+ 0x0d, 0x80, 0x2e, 0x5e, 0x98, 0xf2, 0x71, 0x34,
+ 0x9b, 0x7c, 0xd0, 0xc6, 0x41, 0x04, 0xda, 0x23,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+eddsa_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ eddsa_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = eddsa_pk_new()) == NULL) {
+ warnx("eddsa_pk_new");
+ goto out;
+ }
+ if ((r = eddsa_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("eddsa_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = eddsa_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("eddsa_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ eddsa_pk_free(&k);
+
+ return ok;
+}
+
+static void
+invalid_key(void)
+{
+ EVP_PKEY *pkey;
+ eddsa_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(ecdsa, sizeof(ecdsa))));
+ ASSERT_NOT_NULL((pk = eddsa_pk_new()));
+ ASSERT_INVAL(eddsa_pk_from_EVP_PKEY(pk, pkey));
+
+ EVP_PKEY_free(pkey);
+ eddsa_pk_free(&pk);
+}
+
+static void
+valid_key(void)
+{
+ EVP_PKEY *pkeyA = NULL;
+ EVP_PKEY *pkeyB = NULL;
+ eddsa_pk_t *pkA = NULL;
+ eddsa_pk_t *pkB = NULL;
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f
+ /* incomplete support; test what we can */
+ ASSERT_NULL(EVP_PKEY_from_PEM(eddsa, sizeof(eddsa)));
+ ASSERT_NOT_NULL((pkB = eddsa_pk_new()));
+ ASSERT_INVAL(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw)));
+ ASSERT_NULL(eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw));
+ assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) < 0);
+#else
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(eddsa, sizeof(eddsa))));
+ ASSERT_NOT_NULL((pkA = eddsa_pk_new()));
+ ASSERT_NOT_NULL((pkB = eddsa_pk_new()));
+ ASSERT_OK(eddsa_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw)));
+ ASSERT_NOT_NULL((pkeyB = eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+ assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) == 0);
+#endif
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ eddsa_pk_free(&pkA);
+ eddsa_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ invalid_key();
+ valid_key();
+
+ exit(0);
+}
diff --git a/regress/es256.c b/regress/es256.c
new file mode 100644
index 0000000..3a62a41
--- /dev/null
+++ b/regress/es256.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+#include
+
+#include
+#include
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static const char short_x[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAeeHTZj4LEbt7Czs+u5gEZJfnGE\n"
+"6Z+YLe4AYu7SoGY7IH/2jKifsA7w+lkURL4DL63oEjd3f8foH9bX4eaVug==\n"
+"-----END PUBLIC KEY-----";
+
+static const char short_y[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL8CWUP1r0tpJ5QmkzLc69O74C/Ti\n"
+"83hTiys/JFNVkp0ArW3pKt5jNRrgWSZYE4S/D3AMtpqifFXz/FLCzJqojQ==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char p256k1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEU1y8c0Jg9FGr3vYChpEo9c4dpkijriYM\n"
+"QzU/DeskC89hZjLNH1Sj8ra2MsBlVGGJTNPCZSyx8Jo7ERapxdN7UQ==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char p256v1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n"
+"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const unsigned char p256k1_raw[] = {
+ 0x04, 0x53, 0x5c, 0xbc, 0x73, 0x42, 0x60, 0xf4,
+ 0x51, 0xab, 0xde, 0xf6, 0x02, 0x86, 0x91, 0x28,
+ 0xf5, 0xce, 0x1d, 0xa6, 0x48, 0xa3, 0xae, 0x26,
+ 0x0c, 0x43, 0x35, 0x3f, 0x0d, 0xeb, 0x24, 0x0b,
+ 0xcf, 0x61, 0x66, 0x32, 0xcd, 0x1f, 0x54, 0xa3,
+ 0xf2, 0xb6, 0xb6, 0x32, 0xc0, 0x65, 0x54, 0x61,
+ 0x89, 0x4c, 0xd3, 0xc2, 0x65, 0x2c, 0xb1, 0xf0,
+ 0x9a, 0x3b, 0x11, 0x16, 0xa9, 0xc5, 0xd3, 0x7b,
+ 0x51,
+};
+
+static const unsigned char p256v1_raw[] = {
+ 0x04, 0x3b, 0x08, 0xaa, 0xd7, 0x87, 0x3c, 0xd1,
+ 0xbe, 0xc2, 0xd4, 0x9c, 0xec, 0xc7, 0x9c, 0x35,
+ 0xcc, 0xcb, 0xe4, 0xd8, 0x68, 0x16, 0xe6, 0x47,
+ 0xc6, 0x30, 0xe2, 0x97, 0x8f, 0x01, 0x7f, 0x53,
+ 0xee, 0x75, 0x65, 0xf0, 0x43, 0x29, 0xe8, 0x6c,
+ 0xde, 0x2b, 0xdd, 0x79, 0x70, 0x09, 0x06, 0x4c,
+ 0x48, 0x87, 0xb1, 0x37, 0x88, 0x0d, 0xf6, 0xb3,
+ 0xe1, 0xf2, 0x36, 0xa9, 0x3e, 0x9e, 0xd9, 0x7d,
+ 0x7e,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+es256_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ es256_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = es256_pk_new()) == NULL) {
+ warnx("es256_pk_new");
+ goto out;
+ }
+ if ((r = es256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("es256_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = es256_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("es256_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ es256_pk_free(&k);
+
+ return ok;
+}
+
+static void
+short_coord(void)
+{
+ assert(es256_pk_cmp(short_x, sizeof(short_x)) == 0);
+ assert(es256_pk_cmp(short_y, sizeof(short_y)) == 0);
+}
+
+static void
+invalid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkey;
+ es256_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(p256k1, sizeof(p256k1))));
+ ASSERT_NOT_NULL((pk = es256_pk_new()));
+ ASSERT_INVAL(es256_pk_from_EVP_PKEY(pk, pkey));
+ ASSERT_INVAL(es256_pk_from_ptr(pk, raw, raw_len));
+ ASSERT_NULL(es256_pk_to_EVP_PKEY((const es256_pk_t *)raw));
+
+ EVP_PKEY_free(pkey);
+ es256_pk_free(&pk);
+}
+
+static void
+full_coord(void)
+{
+ assert(es256_pk_cmp(p256v1, sizeof(p256v1)) == 0);
+}
+
+static void
+valid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkeyA;
+ EVP_PKEY *pkeyB;
+ es256_pk_t *pkA;
+ es256_pk_t *pkB;
+
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(p256v1, sizeof(p256v1))));
+ ASSERT_NOT_NULL((pkA = es256_pk_new()));
+ ASSERT_NOT_NULL((pkB = es256_pk_new()));
+ ASSERT_OK(es256_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(es256_pk_from_ptr(pkB, raw, raw_len));
+ ASSERT_NOT_NULL((pkeyB = es256_pk_to_EVP_PKEY(pkB)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ es256_pk_free(&pkA);
+ es256_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ short_coord();
+ full_coord();
+
+ invalid_curve(p256k1_raw, sizeof(p256k1_raw)); /* uncompressed */
+ invalid_curve(p256k1_raw + 1, sizeof(p256k1_raw) - 1); /* libfido2 */
+ valid_curve(p256v1_raw, sizeof(p256v1_raw)); /* uncompressed */
+ valid_curve(p256v1_raw + 1, sizeof(p256v1_raw) - 1); /* libfido2 */
+
+ exit(0);
+}
diff --git a/regress/es384.c b/regress/es384.c
new file mode 100644
index 0000000..b55ce01
--- /dev/null
+++ b/regress/es384.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+#include
+
+#include
+#include
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static const char short_x[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEAAZ/VVCUmFU6aH9kJdDnUHCCglkatFTX\n"
+"onMwIvNYyS8BW/HOoZiOQLs2Hg+qifwaP1pHKILzCVfFmWuZMhxhtmjNXFuOPDnS\n"
+"Wa1PMdkCoWXA2BbXxnqL9v36gIOcFBil\n"
+"-----END PUBLIC KEY-----";
+
+static const char short_y[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuDpRBAg87cnWVhxbWnaWlnj100w9pm5k\n"
+"6T4eYToISaIhEK70TnGwULHX0+qHCYEGACOM7B/ZJbqjo6I7MIXaKZLemGi+tqvy\n"
+"ajBAsTVSyrYBLQjTMMcaFmYmsxvFx7pK\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char brainpoolP384r1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MHowFAYHKoZIzj0CAQYJKyQDAwIIAQELA2IABFKswbBzqqyZ4h1zz8rivqHzJxAO\n"
+"XC2aLyC9x5gwBM7GVu8k6jkX7VypRpg3yyCneiIQ+vVCNXgbDchJ0cPVuhwm3Zru\n"
+"AK49dezUPahWF0YiJRFVeV+KyB/MEaaZvinzqw==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char secp384r1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdJN9DoqPtTNAOmjnECHBIqnJgyBW0rct\n"
+"tbUSqQjb6UG2lldmrQJbgCP/ywuXvkkJl4yfXxOr0UP3rgcnqTVA1/46s2TG+R5u\n"
+"NSQbCM1JPQuvTyFlAn5mdR8ZJJ8yPBQm\n"
+"-----END PUBLIC KEY-----\n";
+
+static const unsigned char brainpoolP384r1_raw[] = {
+ 0x04, 0x52, 0xac, 0xc1, 0xb0, 0x73, 0xaa, 0xac,
+ 0x99, 0xe2, 0x1d, 0x73, 0xcf, 0xca, 0xe2, 0xbe,
+ 0xa1, 0xf3, 0x27, 0x10, 0x0e, 0x5c, 0x2d, 0x9a,
+ 0x2f, 0x20, 0xbd, 0xc7, 0x98, 0x30, 0x04, 0xce,
+ 0xc6, 0x56, 0xef, 0x24, 0xea, 0x39, 0x17, 0xed,
+ 0x5c, 0xa9, 0x46, 0x98, 0x37, 0xcb, 0x20, 0xa7,
+ 0x7a, 0x22, 0x10, 0xfa, 0xf5, 0x42, 0x35, 0x78,
+ 0x1b, 0x0d, 0xc8, 0x49, 0xd1, 0xc3, 0xd5, 0xba,
+ 0x1c, 0x26, 0xdd, 0x9a, 0xee, 0x00, 0xae, 0x3d,
+ 0x75, 0xec, 0xd4, 0x3d, 0xa8, 0x56, 0x17, 0x46,
+ 0x22, 0x25, 0x11, 0x55, 0x79, 0x5f, 0x8a, 0xc8,
+ 0x1f, 0xcc, 0x11, 0xa6, 0x99, 0xbe, 0x29, 0xf3,
+ 0xab,
+};
+
+static const unsigned char secp384r1_raw[] = {
+ 0x04, 0x74, 0x93, 0x7d, 0x0e, 0x8a, 0x8f, 0xb5,
+ 0x33, 0x40, 0x3a, 0x68, 0xe7, 0x10, 0x21, 0xc1,
+ 0x22, 0xa9, 0xc9, 0x83, 0x20, 0x56, 0xd2, 0xb7,
+ 0x2d, 0xb5, 0xb5, 0x12, 0xa9, 0x08, 0xdb, 0xe9,
+ 0x41, 0xb6, 0x96, 0x57, 0x66, 0xad, 0x02, 0x5b,
+ 0x80, 0x23, 0xff, 0xcb, 0x0b, 0x97, 0xbe, 0x49,
+ 0x09, 0x97, 0x8c, 0x9f, 0x5f, 0x13, 0xab, 0xd1,
+ 0x43, 0xf7, 0xae, 0x07, 0x27, 0xa9, 0x35, 0x40,
+ 0xd7, 0xfe, 0x3a, 0xb3, 0x64, 0xc6, 0xf9, 0x1e,
+ 0x6e, 0x35, 0x24, 0x1b, 0x08, 0xcd, 0x49, 0x3d,
+ 0x0b, 0xaf, 0x4f, 0x21, 0x65, 0x02, 0x7e, 0x66,
+ 0x75, 0x1f, 0x19, 0x24, 0x9f, 0x32, 0x3c, 0x14,
+ 0x26,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+es384_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ es384_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = es384_pk_new()) == NULL) {
+ warnx("es384_pk_new");
+ goto out;
+ }
+ if ((r = es384_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("es384_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = es384_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("es384_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ es384_pk_free(&k);
+
+ return ok;
+}
+
+static void
+short_coord(void)
+{
+ assert(es384_pk_cmp(short_x, sizeof(short_x)) == 0);
+ assert(es384_pk_cmp(short_y, sizeof(short_y)) == 0);
+}
+
+static void
+invalid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkey;
+ es384_pk_t *pk;
+
+ pkey = EVP_PKEY_from_PEM(brainpoolP384r1, sizeof(brainpoolP384r1));
+ if (pkey == NULL)
+ return; /* assume no brainpool support in libcrypto */
+ ASSERT_NOT_NULL((pk = es384_pk_new()));
+ ASSERT_INVAL(es384_pk_from_EVP_PKEY(pk, pkey));
+ ASSERT_INVAL(es384_pk_from_ptr(pk, raw, raw_len));
+ ASSERT_NULL(es384_pk_to_EVP_PKEY((const es384_pk_t *)raw));
+
+ EVP_PKEY_free(pkey);
+ es384_pk_free(&pk);
+}
+
+static void
+full_coord(void)
+{
+ assert(es384_pk_cmp(secp384r1, sizeof(secp384r1)) == 0);
+}
+
+static void
+valid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkeyA;
+ EVP_PKEY *pkeyB;
+ es384_pk_t *pkA;
+ es384_pk_t *pkB;
+
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(secp384r1, sizeof(secp384r1))));
+ ASSERT_NOT_NULL((pkA = es384_pk_new()));
+ ASSERT_NOT_NULL((pkB = es384_pk_new()));
+ ASSERT_OK(es384_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(es384_pk_from_ptr(pkB, raw, raw_len));
+ ASSERT_NOT_NULL((pkeyB = es384_pk_to_EVP_PKEY(pkB)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ es384_pk_free(&pkA);
+ es384_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ short_coord();
+ full_coord();
+
+ invalid_curve(brainpoolP384r1_raw, sizeof(brainpoolP384r1_raw)); /* uncompressed */
+ invalid_curve(brainpoolP384r1_raw + 1, sizeof(brainpoolP384r1_raw) - 1); /* libfido2 */
+ valid_curve(secp384r1_raw, sizeof(secp384r1_raw)); /* uncompressed */
+ valid_curve(secp384r1_raw + 1, sizeof(secp384r1_raw) - 1); /* libfido2 */
+
+ exit(0);
+}
diff --git a/regress/rs256.c b/regress/rs256.c
new file mode 100644
index 0000000..799396f
--- /dev/null
+++ b/regress/rs256.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#undef NDEBUG
+
+#include
+#include
+
+#define _FIDO_INTERNAL
+
+#include
+#include
+
+#include
+#include
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static char rsa1024[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw92gn9Ku/bEfFj1AutaZyltpf\n"
+"zzXrg70kQFymNq+spMt/HlxKiImw8TZU08zWW4ZLE/Ch4JYjMW6ETAdQFhSC63Ih\n"
+"Wecui0JJ1f+2CsUVg+h7lO1877LZYUpdNiJrbqMb5Yc4N3FPtvdl3NoLIIQsF76H\n"
+"VRvpjQgkWipRfZ97JQIDAQAB\n"
+"-----END PUBLIC KEY-----";
+
+static char rsa2048[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApvIq/55ZodBIxzo/8BnE\n"
+"UQN1fo1hmJ6V20hQHSzJq5tHyxRCcvKikuJ1ZvR4RdZlEzdTdbEfMBdZ8sxve0/U\n"
+"yYEjH92CG0vgTCYuUaFLJTaWZSvWa96G8Lw+V4VyNFDRCM7sflOaSVH5pAsz8OEc\n"
+"TLZfM4NhnDsJAM+mQ6X7Tza0sczPchgDA+9KByXo/VIqyuBQs17rlKC2reMa8NkY\n"
+"rBRQZJLNzi68d5/BHH1flGWE1l8wJ9dr1Ex93H/KdzX+7/28TWUC98nneUo8RfRx\n"
+"FwUt/EInDMHOORCaCHSs28U/9IUyMjqLB1rxKhIp09yGXMiTrrT+p+Pcn8dO01HT\n"
+"vQIDAQAB\n"
+"-----END PUBLIC KEY-----";
+
+static char rsa3072[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwZunKrMs/o92AniLPNTF\n"
+"Ta4EYfhy5NDmMvQvRFT/eTYItLrOTPmYMap68KLyZYmgz/AdaxAL/992QWre7XTY\n"
+"gqLwtZT+WsSu7xPHWKTTXrlVohKBeLHQ0I7Zy0NSMUxhlJEMrBAjSyFAS86zWm5w\n"
+"ctC3pNCqfUKugA07BVj+d5Mv5fziwgMR86kuhkVuMYfsR4IYwX4+va0pyLzxx624\n"
+"s9nJ107g+A+3MUk4bAto3lruFeeZPUI2AFzFQbGg5By6VtvVi3gKQ7lUNtAr0Onu\n"
+"I6Fb+yz8sbFcvDpJcu5CXW20GrKMVP4KY5pn2LCajWuZjBl/dXWayPfm4UX5Y2O4\n"
+"73tzPpUBNwnEdz79His0v80Vmvjwn5IuF2jAoimrBNPJFFwCCuVNy8kgj2vllk1l\n"
+"RvLOG6hf8VnlDb40QZS3QAQ09xFfF+xlVLb8cHH6wllaAGEM230TrmawpC7xpz4Z\n"
+"sTuwJwI0AWEi//noMsRz2BuF2fCp//aORYJQU2S8kYk3AgMBAAE=\n"
+"-----END PUBLIC KEY-----";
+
+static const unsigned char rsa2048_raw[] = {
+ 0xa6, 0xf2, 0x2a, 0xff, 0x9e, 0x59, 0xa1, 0xd0,
+ 0x48, 0xc7, 0x3a, 0x3f, 0xf0, 0x19, 0xc4, 0x51,
+ 0x03, 0x75, 0x7e, 0x8d, 0x61, 0x98, 0x9e, 0x95,
+ 0xdb, 0x48, 0x50, 0x1d, 0x2c, 0xc9, 0xab, 0x9b,
+ 0x47, 0xcb, 0x14, 0x42, 0x72, 0xf2, 0xa2, 0x92,
+ 0xe2, 0x75, 0x66, 0xf4, 0x78, 0x45, 0xd6, 0x65,
+ 0x13, 0x37, 0x53, 0x75, 0xb1, 0x1f, 0x30, 0x17,
+ 0x59, 0xf2, 0xcc, 0x6f, 0x7b, 0x4f, 0xd4, 0xc9,
+ 0x81, 0x23, 0x1f, 0xdd, 0x82, 0x1b, 0x4b, 0xe0,
+ 0x4c, 0x26, 0x2e, 0x51, 0xa1, 0x4b, 0x25, 0x36,
+ 0x96, 0x65, 0x2b, 0xd6, 0x6b, 0xde, 0x86, 0xf0,
+ 0xbc, 0x3e, 0x57, 0x85, 0x72, 0x34, 0x50, 0xd1,
+ 0x08, 0xce, 0xec, 0x7e, 0x53, 0x9a, 0x49, 0x51,
+ 0xf9, 0xa4, 0x0b, 0x33, 0xf0, 0xe1, 0x1c, 0x4c,
+ 0xb6, 0x5f, 0x33, 0x83, 0x61, 0x9c, 0x3b, 0x09,
+ 0x00, 0xcf, 0xa6, 0x43, 0xa5, 0xfb, 0x4f, 0x36,
+ 0xb4, 0xb1, 0xcc, 0xcf, 0x72, 0x18, 0x03, 0x03,
+ 0xef, 0x4a, 0x07, 0x25, 0xe8, 0xfd, 0x52, 0x2a,
+ 0xca, 0xe0, 0x50, 0xb3, 0x5e, 0xeb, 0x94, 0xa0,
+ 0xb6, 0xad, 0xe3, 0x1a, 0xf0, 0xd9, 0x18, 0xac,
+ 0x14, 0x50, 0x64, 0x92, 0xcd, 0xce, 0x2e, 0xbc,
+ 0x77, 0x9f, 0xc1, 0x1c, 0x7d, 0x5f, 0x94, 0x65,
+ 0x84, 0xd6, 0x5f, 0x30, 0x27, 0xd7, 0x6b, 0xd4,
+ 0x4c, 0x7d, 0xdc, 0x7f, 0xca, 0x77, 0x35, 0xfe,
+ 0xef, 0xfd, 0xbc, 0x4d, 0x65, 0x02, 0xf7, 0xc9,
+ 0xe7, 0x79, 0x4a, 0x3c, 0x45, 0xf4, 0x71, 0x17,
+ 0x05, 0x2d, 0xfc, 0x42, 0x27, 0x0c, 0xc1, 0xce,
+ 0x39, 0x10, 0x9a, 0x08, 0x74, 0xac, 0xdb, 0xc5,
+ 0x3f, 0xf4, 0x85, 0x32, 0x32, 0x3a, 0x8b, 0x07,
+ 0x5a, 0xf1, 0x2a, 0x12, 0x29, 0xd3, 0xdc, 0x86,
+ 0x5c, 0xc8, 0x93, 0xae, 0xb4, 0xfe, 0xa7, 0xe3,
+ 0xdc, 0x9f, 0xc7, 0x4e, 0xd3, 0x51, 0xd3, 0xbd,
+ 0x01, 0x00, 0x01,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+rs256_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ rs256_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = rs256_pk_new()) == NULL) {
+ warnx("rs256_pk_new");
+ goto out;
+ }
+ if ((r = rs256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("rs256_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = rs256_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("rs256_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ rs256_pk_free(&k);
+
+ return ok;
+}
+
+static void
+invalid_size(const char *pem)
+{
+ EVP_PKEY *pkey;
+ rs256_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(pem, strlen(pem))));
+ ASSERT_NOT_NULL((pk = rs256_pk_new()));
+ ASSERT_INVAL(rs256_pk_from_EVP_PKEY(pk, pkey));
+
+ EVP_PKEY_free(pkey);
+ rs256_pk_free(&pk);
+}
+
+static void
+valid_size(const char *pem, const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkeyA;
+ EVP_PKEY *pkeyB;
+ rs256_pk_t *pkA;
+ rs256_pk_t *pkB;
+
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(pem, strlen(pem))));
+ ASSERT_NOT_NULL((pkA = rs256_pk_new()));
+ ASSERT_NOT_NULL((pkB = rs256_pk_new()));
+ ASSERT_OK(rs256_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(rs256_pk_from_ptr(pkB, raw, raw_len));
+ ASSERT_NOT_NULL((pkeyB = rs256_pk_to_EVP_PKEY(pkB)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+ assert(rs256_pk_cmp(pem, strlen(pem)) == 0);
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ rs256_pk_free(&pkA);
+ rs256_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ invalid_size(rsa1024);
+ invalid_size(rsa3072);
+ valid_size(rsa2048, rsa2048_raw, sizeof(rsa2048_raw));
+
+ exit(0);
+}