Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addition of v6 and PQC #35

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ tristate_feature_auto(ENABLE_BLOWFISH "Enable Blowfish cipher support.")
tristate_feature_auto(ENABLE_CAST5 "Enable CAST5 cipher support.")
tristate_feature_auto(ENABLE_RIPEMD160 "Enable RIPEMD-160 hash support.")

option(ENABLE_CRYPTO_REFRESH "Enable crypto-refresh support (v6)")
option(ENABLE_PQC "Enable PQC support - requires ENABLE_CRYPTO_REFRESH")

if((NOT ENABLE_CRYPTO_REFRESH) AND ENABLE_PQC)
message(FATAL_ERROR "ENABLE_PQC requires ENABLE_CRYPTO_REFRESH")
endif()


set(ENABLE_DOC Auto CACHE STRING "Enable building documentation.")
set_property(CACHE ENABLE_DOC PROPERTY STRINGS ${TRISTATE_VALUES})

Expand Down
97 changes: 88 additions & 9 deletions include/repgp/repgp_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define REPGP_DEF_H_

#include <cstdint>
#include "config.h"

/************************************/
/* Packet Tags - RFC4880, 4.2 */
Expand Down Expand Up @@ -94,8 +95,19 @@
#define PGP_KEY_ID_SIZE 8

/* Size of the fingerprint */
#define PGP_FINGERPRINT_SIZE 20
#define PGP_FINGERPRINT_HEX_SIZE (PGP_FINGERPRINT_SIZE * 2) + 1
#define PGP_FINGERPRINT_V4_SIZE 20
falko-strenzke marked this conversation as resolved.
Show resolved Hide resolved
#if defined(ENABLE_CRYPTO_REFRESH)
#define PGP_FINGERPRINT_V6_SIZE 32
#define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V6_SIZE
#else
#define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V4_SIZE
#endif
#define PGP_MAX_FINGERPRINT_HEX_SIZE (PGP_MAX_FINGERPRINT_SIZE * 2) + 1

/* SEIPDv2 salt length */
#ifdef ENABLE_CRYPTO_REFRESH
#define PGP_SEIPDV2_SALT_LEN 32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move it under the define.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand: move what exactly where?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@falko-strenzke As PGP_SEIPDV2_SALT_LEN is used only with ENABLE_CRYPTO_REFRESH, it should be under the #ifdef ENABLE_CRYPTO_REFRESH, so code without ENABLE_CRYPTO_REFRESH doesn't have unused defines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in upcoming commit

#endif

/* Size of the key grip */
#define PGP_KEY_GRIP_SIZE 20
Expand All @@ -104,6 +116,11 @@
#define PGP_MARKER_CONTENTS "PGP"
#define PGP_MARKER_LEN 3

/* V6 Signature Salt */
#if defined(ENABLE_CRYPTO_REFRESH)
#define PGP_MAX_SALT_SIZE_V6_SIG 32
#endif

/** Old Packet Format Lengths.
* Defines the meanings of the 2 bits for length type in the
* old packet format.
Expand Down Expand Up @@ -203,8 +220,43 @@ typedef enum : uint8_t {
* (X9.42, as defined for
* IETF-S/MIME) */
PGP_PKA_EDDSA = 22, /* EdDSA from draft-ietf-openpgp-rfc4880bis */
PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */

#if defined(ENABLE_CRYPTO_REFRESH)
PGP_PKA_X25519 = 25, /* v6 / Crypto Refresh */
PGP_PKA_ED25519 = 27, /* v6 / Crypto Refresh */
#endif

#if defined(ENABLE_PQC)
/* PQC-ECC composite */
PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-02 */
// PGP_PKA_KYBER1024_X448 = 30, /* Kyer1024 + X448 from
// draft-wussler-openpgp-pqc-02 */
PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_KYBER768_BP256 =
33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_KYBER1024_BP384 =
34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-02 */

PGP_PKA_DILITHIUM3_ED25519 =
35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-02 */
// PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from
// draft-wussler-openpgp-pqc-02 */
PGP_PKA_DILITHIUM3_P256 =
37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_DILITHIUM5_P384 =
38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_DILITHIUM3_BP256 =
39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_DILITHIUM5_BP384 =
40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-02 */

PGP_PKA_SPHINCSPLUS_SHA2 = 41, /* SPHINCS+-simple-SHA2 from draft-wussler-openpgp-pqc-02 */
PGP_PKA_SPHINCSPLUS_SHAKE =
42, /* SPHINCS+-simple-SHAKE from draft-wussler-openpgp-pqc-02 */
#endif

PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */
PGP_PKA_PRIVATE00 = 100, /* Private/Experimental Algorithm */
PGP_PKA_PRIVATE01 = 101, /* Private/Experimental Algorithm */
PGP_PKA_PRIVATE02 = 102, /* Private/Experimental Algorithm */
Expand Down Expand Up @@ -388,7 +440,11 @@ typedef enum {
PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE = 32, /* embedded signature */
PGP_SIG_SUBPKT_ISSUER_FPR = 33, /* issuer fingerprint */
PGP_SIG_SUBPKT_PREFERRED_AEAD = 34, /* preferred AEAD algorithms */
PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */
#if defined(ENABLE_CRYPTO_REFRESH)
/* PGP_SIG_SUBPKT_INTENDED_RECIPIENT_FINGERPRINT = 35, */
PGP_SIG_SUBPKT_PREFERRED_AEAD_CIPHERSUITES = 39,
#endif
PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */
PGP_SIG_SUBPKT_PRIVATE_101 = 101,
PGP_SIG_SUBPKT_PRIVATE_102 = 102,
PGP_SIG_SUBPKT_PRIVATE_103 = 103,
Expand Down Expand Up @@ -423,7 +479,10 @@ typedef enum {
typedef enum {
PGP_KEY_FEATURE_MDC = 0x01,
PGP_KEY_FEATURE_AEAD = 0x02,
PGP_KEY_FEATURE_V5 = 0x04
PGP_KEY_FEATURE_V5 = 0x04,
#if defined(ENABLE_CRYPTO_REFRESH)
PGP_KEY_FEATURE_SEIPDV2 = 0x08
#endif
} pgp_key_feature_t;

/** Types of Compression */
Expand All @@ -435,18 +494,30 @@ typedef enum {
PGP_C_UNKNOWN = 255
} pgp_compression_type_t;

enum { PGP_SE_IP_DATA_VERSION = 1, PGP_PKSK_V3 = 3, PGP_SKSK_V4 = 4, PGP_SKSK_V5 = 5 };
enum { PGP_SKSK_V4 = 4, PGP_SKSK_V5 = 5 };
typedef enum {
PGP_PKSK_V3 = 3,
#if defined(ENABLE_CRYPTO_REFRESH)
PGP_PKSK_V6 = 6
#endif
} pgp_pkesk_version_t;
typedef enum { PGP_SE_IP_DATA_V1 = 1, PGP_SE_IP_DATA_V2 = 2 } pgp_seipd_version_t;

/** Version.
* OpenPGP has two different protocol versions: version 3 and version 4.
* Also there is a draft that defines version 5, see
* https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/
*
* \see RFC4880 5.2
*/
typedef enum {
PGP_VUNKNOWN = 0,
PGP_V2 = 2, /* Version 2 (essentially the same as v3) */
PGP_V3 = 3, /* Version 3 */
PGP_V4 = 4 /* Version 4 */
PGP_V4 = 4, /* Version 4 */
#if defined(ENABLE_CRYPTO_REFRESH)
PGP_V6 = 6 /* Version 6 (crypto refresh) */
#endif
} pgp_version_t;

typedef enum pgp_op_t {
Expand Down Expand Up @@ -499,7 +570,15 @@ typedef enum pgp_key_store_format_t {
} pgp_key_store_format_t;

namespace rnp {
enum class AuthType { None, MDC, AEADv1 };
}
enum class AuthType {
None,
MDC,
AEADv1,
#ifdef ENABLE_CRYPTO_REFRESH
AEADv2
#endif
};

} // namespace rnp

#endif
60 changes: 60 additions & 0 deletions include/rnp/rnp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,31 @@ RNP_API rnp_result_t rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op);
RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op,
const char * keyserver);

/** Set the generated key version to v6.
* NOTE: This is an experimantal feature and this function can be replaced (or removed) at any
* time.
*
* @param op pointer to opaque key generation context.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some note that it is for experimental usage only and could be removed or replaced by other function at any time.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a note


/** Set the SPHINCS+ parameter set
* NOTE: This is an experimantal feature and this function can be replaced (or removed) at any
* time.
*
* @param op pointer to opaque key generation context.
* @param param string, representing the SHPINCS+ parameter set.
* Possible Values:
* 128s, 128f, 192s, 192f, 256s, 256f
* All parameter sets refer to the simple variant and the hash function is given
* by the algorithm id.
*
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_op_generate_set_sphincsplus_param(rnp_op_generate_t op,
const char * param);

/** Execute the prepared key or subkey generation operation.
* Note: if you set protection algorithm, then you need to specify ffi password provider to
* be able to request password for key encryption.
Expand Down Expand Up @@ -1716,6 +1741,14 @@ RNP_API rnp_result_t rnp_uid_remove(rnp_key_handle_t key, rnp_uid_handle_t uid);
*/
RNP_API rnp_result_t rnp_uid_handle_destroy(rnp_uid_handle_t uid);

/**
* @brief Get key's version as integer.
*
* @param key key handle, should not be NULL
* @return RNP_SUCCESS or error code on failure.
*/
RNP_API rnp_result_t rnp_key_get_version(rnp_key_handle_t handle, uint32_t *version);

/** Get number of the key's subkeys.
*
* @param key key handle.
Expand Down Expand Up @@ -2972,6 +3005,17 @@ RNP_API rnp_result_t rnp_op_encrypt_create(rnp_op_encrypt_t *op,
*/
RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t key);

/**
* @brief Enables the creation of PKESK v6 (instead of v3) which results in the use of SEIPDv2.
* The actually created version depends on the capabilities of the list of recipients.
* NOTE: This is an experimental feature and this function can be replaced (or removed) at any
* time.
*
* @param op opaque encrypting context. Must be allocated and initialized.
* @return RNP_SUCCESS or errorcode if failed.
*/
RNP_API rnp_result_t rnp_op_encrypt_enable_pkesk_v6(rnp_op_encrypt_t op);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done via rnp_op_encrypt_set_flags(). However, adding some note that this is experimental and could be replaced or removed would also work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a note for now. If you prefer the other option I can do that as well.


/**
* @brief Add signature to encrypting context, so data will be encrypted and signed.
*
Expand Down Expand Up @@ -3368,6 +3412,22 @@ RNP_API const char *rnp_backend_version();
#define RNP_ALGNAME_ECDH "ECDH"
#define RNP_ALGNAME_ECDSA "ECDSA"
#define RNP_ALGNAME_EDDSA "EDDSA"
#define RNP_ALGNAME_ED25519 "ED25519"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put these new defines under the PQC ifdef.

Copy link
Collaborator

@TJ-91 TJ-91 Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to add #include "config.h" here s.t. the defines are set. Is that ok for this file?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TJ-91 Sorry, somehow mislooked your comment. Now I realize that this will not work - config.h is not installed to /usr/include/, so attempt to compile code which uses rnp.h will fail, unless I mislooked something. Wondering what would be the correct solution...

#define RNP_ALGNAME_X25519 "X25519"
#define RNP_ALGNAME_KYBER768_X25519 "KYBER768_X25519"
#define RNP_ALGNAME_KYBER1024_X448 "KYBER1024_X448"
#define RNP_ALGNAME_KYBER768_P256 "KYBER768_P256"
#define RNP_ALGNAME_KYBER1024_P384 "KYBER1024_P384"
#define RNP_ALGNAME_KYBER768_BP256 "KYBER768_BP256"
#define RNP_ALGNAME_KYBER1024_BP384 "KYBER1024_BP384"
#define RNP_ALGNAME_DILITHIUM3_ED25519 "DILITHIUM3_ED25519"
#define RNP_ALGNAME_DILITHIUM5_ED448 "DILITHIUM5_ED448"
#define RNP_ALGNAME_DILITHIUM3_P256 "DILITHIUM3_P256"
#define RNP_ALGNAME_DILITHIUM5_P384 "DILITHIUM5_P384"
#define RNP_ALGNAME_DILITHIUM3_BP256 "DILITHIUM3_BP256"
#define RNP_ALGNAME_DILITHIUM5_BP384 "DILITHIUM5_BP384"
#define RNP_ALGNAME_SPHINCSPLUS_SHA2 "SPHINCSPLUS_SHA2"
#define RNP_ALGNAME_SPHINCSPLUS_SHAKE "SPHINCSPLUS_SHAKE"
#define RNP_ALGNAME_IDEA "IDEA"
#define RNP_ALGNAME_TRIPLEDES "TRIPLEDES"
#define RNP_ALGNAME_CAST5 "CAST5"
Expand Down
1 change: 1 addition & 0 deletions include/rnp/rnp_err.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum {
RNP_ERROR_KEY_NOT_FOUND,
RNP_ERROR_NO_SUITABLE_KEY,
RNP_ERROR_DECRYPT_FAILED,
RNP_ERROR_ENCRYPT_FAILED,
RNP_ERROR_RNG,
RNP_ERROR_SIGNING_FAILED,
RNP_ERROR_NO_SIGNATURES_FOUND,
Expand Down
53 changes: 52 additions & 1 deletion src/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ if(CRYPTO_BACKEND_BOTAN3)
set(CMAKE_CXX_STANDARD 20)
endif()

if(ENABLE_PQC)
Copy link
Collaborator

@ni4 ni4 Aug 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check here or somewhere else for Botan version 3.1.0 (SPHINCS support) ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not handled in the line that follows?

  if (NOT CRYPTO_BACKEND_BOTAN3)
    message(FATAL_ERROR "ENABLE_PQC requires Botan 3 as crypto backend")
  endif()

We can update the find_package command to 3.1.0 (instead of 3.0.0), would that suffice?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TJ-91 Yeah, that would work (if added only for PQC, allowing any vesion of Botan for non-PQC).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left it at checking for 3.0.0 in the find_package() command. If PQC is enabled, the features are checked: resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM;KYBER;SPHINCS_PLUS_WITH_SHA2;SPHINCS_PLUS_WITH_SHAKE"). This means 3.0.0 is fine as long as PQC is disabled. If PQC is enabled, 3.0.0 will fail due to features.

if (NOT CRYPTO_BACKEND_BOTAN3)
message(FATAL_ERROR "ENABLE_PQC requires Botan 3 as crypto backend")
endif()
if (NOT ENABLE_CRYPTO_REFRESH)
message(FATAL_ERROR "ENABLE_PQC requires ENABLE_CRYPTO_REFRESH")
endif()
endif()

# check that AEAD is enabled and not turned off for ENABLE_CRYPTO_REFRESH
if(ENABLE_CRYPTO_REFRESH AND (NOT ENABLE_AEAD))
message(FATAL_ERROR "ENABLE_CRYPTO_REFRESH requires ENABLE_AEAD, but it's either Off or Auto and got turned off")
endif()

# generate a config.h
include(CheckIncludeFileCXX)
include(CheckCXXSymbolExists)
Expand Down Expand Up @@ -173,10 +187,14 @@ if(CRYPTO_BACKEND_BOTAN)
resolve_feature_state(ENABLE_AEAD "AEAD_EAX;AEAD_OCB")
resolve_feature_state(ENABLE_TWOFISH "TWOFISH")
resolve_feature_state(ENABLE_IDEA "IDEA")
# Botan supports Brainpool curves together with SECP via the ECC_GROUP define
resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF")
resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM;KYBER;SPHINCS_PLUS_WITH_SHA2;SPHINCS_PLUS_WITH_SHAKE")
resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH")
resolve_feature_state(ENABLE_CAST5 "CAST_128")
resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160")
# Botan supports Brainpool curves together with SECP via the ECC_GROUP define


set(CMAKE_REQUIRED_INCLUDES)
endif()
if(CRYPTO_BACKEND_OPENSSL)
Expand Down Expand Up @@ -212,6 +230,8 @@ if(CRYPTO_BACKEND_OPENSSL)
openssl_nope(ENABLE_SM2 "it's on our roadmap, see https://github.com/rnpgp/rnp/issues/1877")
#resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4-ECB")
openssl_nope(ENABLE_TWOFISH "Twofish isn't and won't be supported by OpenSSL, see https://github.com/openssl/openssl/issues/2046")
openssl_nope(ENABLE_CRYPTO_REFRESH, "not yet implemented")
openssl_nope(ENABLE_PQC, "not yet implemented")
endif()

configure_file(config.h.in config.h)
Expand Down Expand Up @@ -271,6 +291,28 @@ elseif(CRYPTO_BACKEND_BOTAN)
if(ENABLE_SM2)
list(APPEND CRYPTO_SOURCES crypto/sm2.cpp)
endif()
if(ENABLE_CRYPTO_REFRESH)
list(APPEND CRYPTO_SOURCES
crypto/hkdf.cpp
crypto/hkdf_botan.cpp
crypto/ed25519.cpp
crypto/x25519.cpp
crypto/exdsa_ecdhkem.cpp
)
endif()
if(ENABLE_PQC)
list(APPEND CRYPTO_SOURCES
crypto/dilithium.cpp
crypto/dilithium_common.cpp
crypto/sphincsplus.cpp
crypto/kyber_common.cpp
crypto/kyber.cpp
crypto/kyber_ecdh_composite.cpp
crypto/dilithium_exdsa_composite.cpp
crypto/kmac.cpp
crypto/kmac_botan.cpp
)
endif()
else()
message(FATAL_ERROR "Unknown crypto backend: ${CRYPTO_BACKEND}.")
endif()
Expand All @@ -279,6 +321,14 @@ list(APPEND CRYPTO_SOURCES crypto/backend_version.cpp)
# sha11collisiondetection sources
list(APPEND CRYPTO_SOURCES crypto/hash_sha1cd.cpp crypto/sha1cd/sha1.c crypto/sha1cd/ubc_check.c)


set(CRYPTO_REFRESH_SOURCES )
if(ENABLE_CRYPTO_REFRESH)
list(APPEND CRYPTO_REFRESH_SOURCES
../librepgp/v2_seipd.cpp
)
endif()

add_library(librnp-obj OBJECT
# librepgp
../librepgp/stream-armor.cpp
Expand All @@ -290,6 +340,7 @@ add_library(librnp-obj OBJECT
../librepgp/stream-parse.cpp
../librepgp/stream-sig.cpp
../librepgp/stream-write.cpp
${CRYPTO_REFRESH_SOURCES}

# librekey
../librekey/key_store_g10.cpp
Expand Down
9 changes: 9 additions & 0 deletions src/lib/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
#cmakedefine ENABLE_TWOFISH
#cmakedefine ENABLE_BRAINPOOL
#cmakedefine ENABLE_IDEA
#cmakedefine ENABLE_CRYPTO_REFRESH
#cmakedefine ENABLE_PQC
#cmakedefine ENABLE_BLOWFISH
#cmakedefine ENABLE_CAST5
#cmakedefine ENABLE_RIPEMD160
Expand All @@ -71,3 +73,10 @@
((defined(__clang__) && (__clang_major__ >= 4)) )
#define RNP_USE_STD_REGEX 1
#endif

/* do not use the statement for old MSVC versions */
#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L)
# define FALLTHROUGH_STATEMENT [[fallthrough]];
#else
# define FALLTHROUGH_STATEMENT
#endif
Loading