1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/include/fido2/ctap/ctap.h
2021-09-08 15:22:40 +02:00

675 lines
22 KiB
C

/*
* Copyright (C) 2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup fido2_ctap_ctap FIDO2 CTAP
* @ingroup fido2_ctap
* @brief FIDO2 CTAP
*
* The Client-to-Authenticator Protocol (CTAP) is an application layer protocol
* for the communication between an authenticator and a host.
*
* @{
*
* @file
* @brief Internal FIDO2 CTAP defines, structures and function declarations
*
* @author Nils Ollrogge <nils.ollrogge@fu-berlin.de>
*/
#ifndef FIDO2_CTAP_CTAP_H
#define FIDO2_CTAP_CTAP_H
#include <stdint.h>
#include "mutex.h"
#include "cbor.h"
#include "assert.h"
#include "crypto/modes/ccm.h"
#include "timex.h"
#include "board.h"
#include "fido2/ctap.h"
#include "fido2/ctap/ctap_crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Size of pin auth
*
* First 16 bytes of a HMAC-256.
*
* CTAP specification (version 20190130) section 5.5.8.2.
*/
#define CTAP_PIN_AUTH_SZ 16
/**
* @name CTAP methods
*
* @{
*/
#define CTAP_MAKE_CREDENTIAL 0x01 /**< authenticatorMakeCredential method */
#define CTAP_GET_ASSERTION 0x02 /**< authenticatorGetAssertion method */
#define CTAP_GET_INFO 0x04 /**< authenticatorGetInfo method */
#define CTAP_CLIENT_PIN 0x06 /**< authenticatorClientPIN method */
#define CTAP_RESET 0x07 /**< authenticatorReset method */
#define CTAP_GET_NEXT_ASSERTION 0x08 /**< authenticatorGetNextAssertion method */
/** @} */
/**
* @name CTAP authenticator data option flags
*
* @{
*/
#define CTAP_AUTH_DATA_FLAG_UP (1 << 0) /**< user present */
#define CTAP_AUTH_DATA_FLAG_UV (1 << 2) /**< user verified */
#define CTAP_AUTH_DATA_FLAG_AT (1 << 6) /**< attested credential data included */
#define CTAP_AUTH_DATA_FLAG_ED (1 << 7) /**< extension data included */
/** @} */
/**
* @name CTAP version flags
*
* @{
*/
#define CTAP_VERSION_FLAG_FIDO_PRE 0x01 /**< FIDO 2.1 flag */
#define CTAP_VERSION_FLAG_FIDO 0x02 /**< FIDO 2 flag */
#define CTAP_VERSION_FLAG_U2F_V2 0x04 /**< U2F V2 flag */
/** @} */
/**
* @name CTAP get info response options map CBOR key values
*
* All options are in the form key-value pairs with string IDs and
* boolean values
* @{
*/
#define CTAP_GET_INFO_RESP_OPTIONS_ID_PLAT "plat" /**< platform device string */
#define CTAP_GET_INFO_RESP_OPTIONS_ID_RK "rk" /**< resident key string */
#define CTAP_GET_INFO_RESP_OPTIONS_ID_CLIENT_PIN "clientPin" /**< client PIN string */
#define CTAP_GET_INFO_RESP_OPTIONS_ID_UP "up" /**< user presence string */
#define CTAP_GET_INFO_RESP_OPTIONS_ID_UV "uv" /**< user verification string */
/** @} */
/**
* @name CTAP get info options flags
*
* @{
*/
#define CTAP_INFO_OPTIONS_FLAG_PLAT (1 << 0) /**< platform device flag */
#define CTAP_INFO_OPTIONS_FLAG_RK (1 << 1) /**< resident key flag */
#define CTAP_INFO_OPTIONS_FLAG_CLIENT_PIN (1 << 2) /**< clientPIN flag */
#define CTAP_INFO_OPTIONS_FLAG_UP (1 << 3) /**< user presence flag */
#define CTAP_INFO_OPTIONS_FLAG_UV (1 << 4) /**< user verification flag */
/** @} */
/**
* @name CTAP Client PIN request subCommand CBOR key values
*
* @{
*/
#define CTAP_CP_REQ_SUB_COMMAND_GET_RETRIES 0x01 /**< getRetries subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_GET_KEY_AGREEMENT 0x02 /**< getKeyAgreement subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_SET_PIN 0x03 /**< setPIN subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_CHANGE_PIN 0x04 /**< changePIN subCommand */
#define CTAP_CP_REQ_SUB_COMMAND_GET_PIN_TOKEN 0x05 /**< getPinToken subCommand */
/** @} */
/**
* @brief CTAP thread stack size
*/
#ifdef CONFIG_FIDO2_CTAP_STACK_SIZE
#define CTAP_STACKSIZE CONFIG_FIDO2_CTAP_STACK_SIZE
#else
#define CTAP_STACKSIZE 15000
#endif
#if !IS_ACTIVE(CONFIG_FIDO2_CTAP_DISABLE_UP)
/**
* @brief CTAP user presence button
*/
#if defined(CONFIG_FIDO2_CTAP_UP_BUTTON_PORT) && defined(CONFIG_FIDO2_CTAP_UP_BUTTON_PIN) && \
(CONFIG_FIDO2_CTAP_UP_BUTTON_PORT >= 0) && (CONFIG_FIDO2_CTAP_UP_BUTTON_PIN >= 0)
#define CTAP_UP_BUTTON GPIO_PIN(CONFIG_FIDO2_CTAP_UP_BUTTON_PORT, CONFIG_FIDO2_CTAP_UP_BUTTON_PIN)
#else
/* set default button if no button is configured */
#ifdef BTN0_PIN
#define CTAP_UP_BUTTON BTN0_PIN
/* if no button available disable UP test */
#else
#define CONFIG_FIDO2_CTAP_DISABLE_UP 1
#endif
#endif
/**
* @brief CTAP user presence button mode
*/
#if IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_MODE_IN_PU)
#define CTAP_UP_BUTTON_MODE GPIO_IN_PU
#elif IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_MODE_IN_PD)
#define CTAP_UP_BUTTON_MODE GPIO_IN_PD
#elif IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_MODE_IN)
#define CTAP_UP_BUTTON_MODE GPIO_IN
#else
#define CTAP_UP_BUTTON_MODE GPIO_IN_PU
#endif
/**
* @brief CTAP user presence button flank
*/
#if IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_FLANK_FALLING)
#define CTAP_UP_BUTTON_FLANK GPIO_FALLING
#elif IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_FLANK_RISING)
#define CTAP_UP_BUTTON_FLANK GPIO_RISING
#elif IS_ACTIVE(CONFIG_FIDO2_CTAP_UP_BUTTON_FLANK_BOTH)
#define CTAP_UP_BUTTON_FLANK GPIO_BOTH
#else
#define CTAP_UP_BUTTON_FLANK GPIO_FALLING
#endif
#endif /* !IS_ACTIVE(CONFIG_FIDO2_CTAP_DISABLE_UP) */
/**
* @brief Max size of relying party name
*/
#define CTAP_RP_MAX_NAME_SIZE 32
/**
* @brief Max size of username including null character
*/
#define CTAP_USER_MAX_NAME_SIZE 64 + 1
/**
* @brief Max size of user id
*/
#define CTAP_USER_ID_MAX_SIZE 64
/**
* @brief Max size of a domain name including null character
*/
#define CTAP_DOMAIN_NAME_MAX_SIZE 253 + 1
/**
* @brief Max size of icon including null character
*/
#define CTAP_ICON_MAX_SIZE 128 + 1
/**
* @brief PIN min size
*/
#define CTAP_PIN_MIN_SIZE 4
/**
* @brief Encrypted newPin min size
*
* Encrypted PIN is padded with trailing 0x00 bytes to a minimum length
* of 64 in order to prevent leak of PIN length.
*/
#define CTAP_PIN_ENC_MIN_SIZE 64
/**
* @brief Encrypted newPin max size
*
*/
#define CTAP_PIN_ENC_MAX_SIZE 256
/**
* @brief PIN max size
*/
#define CTAP_PIN_MAX_SIZE 64
/**
* @brief Max total consecutive incorrect PIN attempts
*/
#define CTAP_PIN_MAX_ATTS 8
/**
* @brief Max consecutive incorrect PIN attempts for 1 boot cycle
*/
#define CTAP_PIN_MAX_ATTS_BOOT 3
/**
* @brief PIN protocol version
*/
#define CTAP_PIN_PROT_VER 1
/**
* @brief Total number of supported PIN protocol versions
*/
#define CTAP_AMT_SUP_PIN_VER 1
/**
* @brief Size of pin token
*
* Needs to be a multiple of 16 bytes (AES block length).
*/
#define CTAP_PIN_TOKEN_SZ 16
/**
* @brief Size of key used to encrypt credential
*
* Needed if authenticator is unable to store resident keys.
* See webauthn specification (version 20190304) section 4 (Credential ID)
* for details.
*/
#define CTAP_CRED_KEY_LEN 16
/**
* @brief AES_CCM_L parameter
*
* L has to be between 2 and 8. Value of 2 means that message has to be
* in the range 0 <= l(m) < 2^(16) = 65536.
* This should always be sufficient to send an encrypted resident key.
*/
#define CTAP_AES_CCM_L 2
/**
* @brief AES CCM nonce size
*/
#define CTAP_AES_CCM_NONCE_SIZE (15 - CTAP_AES_CCM_L)
/**
* @brief Total size of AES CCM credential id
*
* Size of encrypted resident key = resident key - cred id - has_nonce
*/
#define CTAP_CREDENTIAL_ID_ENC_SIZE (sizeof(struct ctap_resident_key) - \
sizeof(((struct ctap_resident_key *)0)-> \
cred_desc.cred_id) - \
sizeof(((struct ctap_resident_key *)0)-> \
cred_desc.has_nonce))
/**
* @brief Timeout for user presence test
*/
#ifdef CONFIG_FIDO2_CTAP_UP_TIMEOUT
#define CTAP_UP_TIMEOUT (CONFIG_FIDO2_CTAP_UP_TIMEOUT * MS_PER_SEC)
#else
#define CTAP_UP_TIMEOUT (15 * MS_PER_SEC)
#endif
/**
* @brief Max time between call to get_assertion or get_next_assertion until
* error is returned
*/
#define CTAP_GET_NEXT_ASSERTION_TIMEOUT (30 * MS_PER_SEC)
/**
* 128 bit identifier of authenticator
*/
#ifdef CONFIG_FIDO2_CTAP_DEVICE_AAGUID
#define CTAP_AAGUID CONFIG_FIDO2_CTAP_DEVICE_AAGUID
#else
/* randomly generated fallback value */
#define CTAP_AAGUID "9c295865fa2c36b705a42320af9c8f16"
#endif
/**
* @name CTAP credential types
*
* @{
*/
#define CTAP_PUB_KEY_CRED_PUB_KEY 0x01 /**< public key credential type */
#define CTAP_PUB_KEY_CRED_UNKNOWN 0x02 /**< unknown credential type */
/** @} */
/**
* @name CTAP COSE key CBOR map key values
*
* @{
*/
#define CTAP_COSE_KEY_LABEL_KTY 1 /**< key type identifier */
#define CTAP_COSE_KEY_LABEL_ALG 3 /**< algorithm identifier */
#define CTAP_COSE_KEY_LABEL_CRV -1 /**< elliptic curve identifier */
#define CTAP_COSE_KEY_LABEL_X -2 /**< x coordinate */
#define CTAP_COSE_KEY_LABEL_Y -3 /**< y coordinate */
#define CTAP_COSE_KEY_KTY_EC2 2 /**< 2 coordinate elliptic curve key identifier */
#define CTAP_COSE_KEY_CRV_P256 1 /**< secp256r1 elliptic curve key identifier */
/** @} */
/**
* @brief CTAP size of authenticator AAGUID in bytes
*/
#define CTAP_AAGUID_SIZE 16
/**
* @brief CTAP COSE Algorithms registry identifier for ES256
*/
#define CTAP_COSE_ALG_ES256 -7
/**
* @brief CTAP COSE Algorithms registry identifier for ECDH ES HKDF 256
*/
#define CTAP_COSE_ALG_ECDH_ES_HKDF_256 -25
/**
* @brief CTAP size of credential id
*
*/
#define CTAP_CREDENTIAL_ID_SIZE 16U
/**
* @brief CTAP state initialized marker
*
* Used to check if authenticator state has already been initialized when
* reading data from flash.
*/
#define CTAP_INITIALIZED_MARKER 0x4e
/**
* @brief Max size of allow list
*/
#define CTAP_MAX_EXCLUDE_LIST_SIZE 0x10
/**
* @brief CTAP cred struct forward declaration
*/
typedef struct ctap_cred_desc ctap_cred_desc_t;
/**
* @brief Alternative CTAP cred struct forward declaration
*/
typedef struct ctap_cred_desc_alt ctap_cred_desc_alt_t;
/**
* @brief CTAP resident key credential forward declaration
*/
typedef struct ctap_resident_key ctap_resident_key_t;
/**
* @brief CTAP authenticator config struct
*/
typedef struct {
uint8_t aaguid[CTAP_AAGUID_SIZE]; /**< AAGUID of device */
uint8_t options; /**< options */
} ctap_config_t;
/**
* @brief CTAP state struct
*
* state of authenticator. Stored in flash memory
*/
typedef struct {
ctap_config_t config; /**< configuration of authenticator */
ctap_crypto_key_agreement_key_t ag_key; /**< Platform key agreement key */
int rem_pin_att; /**< remaining PIN tries */
uint16_t rk_amount_stored; /**< total number of resident keys stored on device */
uint8_t initialized_marker; /**< CTAP initialized marker */
uint8_t pin_hash[SHA256_DIGEST_LENGTH / 2]; /**< LEFT(SHA-256(pin), 16) */
uint8_t cred_key[CTAP_CRED_KEY_LEN]; /**< AES CCM encryption key for cred */
bool cred_key_is_initialized; /**< AES CCM key initialized flag */
bool pin_is_set; /**< PIN is set or not */
} ctap_state_t;
/**
* @brief CTAP options struct
*/
typedef struct {
int rk; /**< resident key */
int uv; /**< user verification */
int up; /**< user presence */
} ctap_options_t;
/**
* @brief CTAP user entity struct
*/
typedef struct {
uint8_t id[CTAP_USER_ID_MAX_SIZE]; /**< RP-specific user account id */
uint8_t id_len; /**< actual length of user id */
uint8_t name[CTAP_USER_MAX_NAME_SIZE]; /**< user name */
uint8_t display_name[CTAP_USER_MAX_NAME_SIZE]; /**< user display name */
uint8_t icon[CTAP_DOMAIN_NAME_MAX_SIZE]; /**< URL referencing user icon image */
} ctap_user_ent_t;
/**
* @brief CTAP relying party entity struct
*
*/
typedef struct {
uint8_t id[CTAP_DOMAIN_NAME_MAX_SIZE + 1]; /**< relying party identifier */
uint8_t id_len; /**< actual length of
relying party identifier */
uint8_t name[CTAP_RP_MAX_NAME_SIZE + 1]; /**< human friendly relying
party name */
uint8_t icon[CTAP_DOMAIN_NAME_MAX_SIZE + 1]; /**< URL referencing relying
party icon image */
} ctap_rp_ent_t;
/**
* @brief CTAP cose key struct
*
* https://www.iana.org/assignments/cose/cose.xhtml
*/
typedef struct {
ctap_crypto_pub_key_t pubkey; /**< public key */
int kty; /**< identification of key type */
int crv; /**< EC identifier */
int32_t alg_type; /**< COSEAlgorithmIdentifier */
uint8_t cred_type; /**< type of credential */
} ctap_public_key_cose_t;
/**
* @brief CTAP credential description struct
*
* Webauthn specification (version 20190304) section 5.8.3
*
* @warning reordering this struct will break the AES CCM encryption of
* resident keys.
*/
struct ctap_cred_desc {
uint8_t cred_type; /**< type of credential */
union {
uint8_t cred_id[CTAP_CREDENTIAL_ID_SIZE]; /**< credential identifier */
uint8_t nonce[CTAP_AES_CCM_NONCE_SIZE]; /**< CTAP AES CCM nonce */
};
bool has_nonce; /**< Indicate if nonce or
cred_id */
};
/**
* @brief CTAP resident key struct
*
* A resident key is a fido2 credential that is being stored on the
* authenticator.
*/
struct __attribute__((packed)) ctap_resident_key {
uint8_t rp_id_hash[SHA256_DIGEST_LENGTH]; /**< hash of rp domain string */
uint8_t user_id[CTAP_USER_ID_MAX_SIZE]; /**< id of user */
uint8_t user_id_len; /**< length of the user id */
uint8_t priv_key[CTAP_CRYPTO_KEY_SIZE]; /**< private key */
uint32_t sign_count; /**< signature counter.
See webauthn specification
(version 20190304) section 6.1.1
for details. */
uint32_t creation_time; /**< timestamp for when credential
was created */
ctap_cred_desc_t cred_desc; /**< credential descriptor */
};
/**
* @brief CTAP credential ID
*
* Credential ID can either be 16 random bytes or the encrypted resident
* key. (AES CCM cipher + mac + nonce used)
*/
typedef struct __attribute__((packed)) {
uint8_t id[CTAP_CREDENTIAL_ID_ENC_SIZE]; /**< id */
uint8_t mac[CCM_MAC_MAX_LEN]; /**< AES CCM MAC */
uint8_t nonce[CTAP_AES_CCM_NONCE_SIZE]; /**< AES CCM nonce */
} ctap_cred_id_t;
/**
* @brief CTAP credential description alternative struct
*
* This struct is used when parsing an allow or exclude list.
*/
struct ctap_cred_desc_alt {
uint8_t cred_type; /**< type of credential */
ctap_cred_id_t cred_id; /**< credential id */
};
/**
* @brief CTAP make credential request struct
*/
typedef struct {
ctap_cred_desc_alt_t exclude_list[CTAP_MAX_EXCLUDE_LIST_SIZE]; /**< exclude list */
size_t exclude_list_len; /**< length of CBOR exclude list array */
ctap_rp_ent_t rp; /**< relying party */
ctap_user_ent_t user; /**< user */
ctap_options_t options; /**< parameters to influence authenticator operation */
uint8_t client_data_hash[SHA256_DIGEST_LENGTH]; /**< SHA-256 hash of JSON serialized client data */
uint8_t pin_auth[CTAP_PIN_AUTH_SZ]; /**< pin_auth if PIN is set */
size_t pin_auth_len; /**< pin_auth len */
int32_t alg_type; /**< cryptographic algorithm identifier */
bool pin_auth_present; /**< pin_auth present */
uint8_t pin_protocol; /**< PIN protocol version */
uint8_t cred_type; /**< type of credential */
} ctap_make_credential_req_t;
/**
* @brief CTAP get assertion request struct
*/
typedef struct {
ctap_options_t options; /**< parameters to influence authenticator operation */
ctap_cred_desc_alt_t allow_list[CTAP_MAX_EXCLUDE_LIST_SIZE]; /**< allow list */
uint8_t client_data_hash[SHA256_DIGEST_LENGTH]; /**< SHA-256 hash of JSON serialized client data */
uint8_t rp_id[CTAP_DOMAIN_NAME_MAX_SIZE + 1]; /**< Relying Party Identifier */
uint8_t rp_id_len; /**< Actual Length of Relying Party Identifier */
uint8_t allow_list_len; /**< length of CBOR allow list array */
uint8_t pin_auth[CTAP_PIN_AUTH_SZ]; /**< pin_auth if PIN is set */
size_t pin_auth_len; /**< pin_auth length */
uint8_t pin_protocol; /**< PIN protocol version */
bool pin_auth_present; /**< indicate if pin_auth present */
} ctap_get_assertion_req_t;
/**
* @brief CTAP client pin request struct
*/
typedef struct {
ctap_public_key_cose_t key_agreement; /**< public key of platform_key_agreement_key*/
uint16_t new_pin_enc_size; /**< size of encrypted new pin */
uint8_t pin_auth[CTAP_PIN_AUTH_SZ]; /**< first 16 bytes of HMAC-SHA-256 of encrypted contents */
uint8_t new_pin_enc[CTAP_PIN_ENC_MAX_SIZE]; /**< Encrypted new PIN using sharedSecret. */
uint8_t pin_hash_enc[SHA256_DIGEST_LENGTH / 2]; /**< Encrypted first 16 bytes of SHA-256 of PIN using sharedSecret. */
uint8_t sub_command; /**< authenticator Client PIN sub command */
uint8_t pin_protocol; /**< PIN protocol version chosen by the client */
bool pin_hash_enc_present; /**< indicate pin_hash_enc is present */
bool pin_auth_present; /**< indicate if pin_auth present */
bool key_agreement_present; /**< indicate if key_agreement present */
} ctap_client_pin_req_t;
/**
* @brief CTAP attested credential data header struct
*
* Defined for easier serialization
*/
typedef struct __attribute__((packed)){
uint8_t aaguid[CTAP_AAGUID_SIZE]; /**< authenticator aaguid */
uint8_t cred_len_h; /**< higher byte of credential length */
uint8_t cred_len_l; /**< lower byte of credential length */
ctap_cred_id_t cred_id; /**< credential id */
} ctap_attested_cred_data_header_t;
/**
* @brief CTAP attested credential data struct
*/
typedef struct {
ctap_attested_cred_data_header_t header; /**< attested credential data header */
ctap_public_key_cose_t key; /**< cose key */
} ctap_attested_cred_data_t;
/**
* @brief CTAP authenticator data header struct
*
* Defined for easier serialization
*/
typedef struct __attribute__((packed)){
uint8_t rp_id_hash[SHA256_DIGEST_LENGTH]; /**< hash of relying party id */
uint8_t flags; /**< flags indicating result of user verification */
uint32_t sign_count; /**< sign count of credential */
} ctap_auth_data_header_t;
/**
* @brief CTAP authenticator data struct
*/
typedef struct {
ctap_auth_data_header_t header; /**< auth data header */
ctap_attested_cred_data_t attested_cred_data; /**< attested credential data */
} ctap_auth_data_t;
/**
* @brief CTAP info struct
*/
typedef struct {
uint16_t max_msg_size; /**< max message size */
uint8_t aaguid[CTAP_AAGUID_SIZE]; /**< AAGUID */
uint8_t versions; /**< supported versions of FIDO */
uint8_t options; /**< supported options */
uint8_t pin_protocol; /**< supported PIN protocol versions */
bool pin_is_set; /**< PIN is set or not */
} ctap_info_t;
/**
* @brief Create signature from authenticator data
*
* Used for attestation and assertion statement.
*
* @param[in] auth_data authenticator data
* @param[in] auth_data_len length of @p auth_data
* @param[in] client_data_hash hash of client data sent by relying party in request
* @param[in] rk resident key used to sign the data
* @param[in] sig signature buffer
* @param[in] sig_len length of @p sig
*
* @return @ref ctap_status_codes_t
*/
int fido2_ctap_get_sig(const uint8_t *auth_data, size_t auth_data_len,
const uint8_t *client_data_hash,
const ctap_resident_key_t *rk,
uint8_t *sig, size_t *sig_len);
/**
* @brief Check if requested algorithm is supported
*
* @param[in] cred_type type of credential
* @param[in] alg_type cryptographic algorithm identifier
*
* @return true if algorithm is supported
* @return false otherwise
*/
bool fido2_ctap_cred_params_supported(uint8_t cred_type, int32_t alg_type);
/**
* @brief Encrypt resident key with AES CCM
*
* @param[in] rk type of credential
* @param[in] nonce CCM nonce
* @param[in] nonce_len length of @p nonce
* @param[in] id credential id struct storing encrypted resident key
*
* @return @ref ctap_status_codes_t
*/
int fido2_ctap_encrypt_rk(ctap_resident_key_t *rk, uint8_t *nonce,
size_t nonce_len, ctap_cred_id_t *id);
/**
* @brief Check if PIN has been set on authenticator
*
* @return true if PIN has been set
* @return false otherwise
*/
bool fido2_ctap_pin_is_set(void);
#ifdef __cplusplus
}
#endif
#endif /* FIDO2_CTAP_CTAP_H */
/** @} */