diff --git a/src/UDPC_Defines.hpp b/src/UDPC_Defines.hpp index 0854ae7..6afde2d 100644 --- a/src/UDPC_Defines.hpp +++ b/src/UDPC_Defines.hpp @@ -209,6 +209,8 @@ public: std::atomic_bool isReceivingEvents; std::atomic_uint32_t protocolID; std::atomic_uint_fast8_t loggingType; + // See UDPC_AuthPolicy enum in UDPConnection.h for possible values + std::atomic_uint_fast8_t authPolicy; std::atomic_uint32_t atostrBufIndex; char atostrBuf[UDPC_ATOSTR_SIZE]; diff --git a/src/UDPConnection.cpp b/src/UDPConnection.cpp index a9d50fc..c2501c7 100644 --- a/src/UDPConnection.cpp +++ b/src/UDPConnection.cpp @@ -1159,6 +1159,28 @@ void UDPC::Context::update_impl() { && conMap.find(identifier) == conMap.end() && isAcceptNewConnections.load()) { // is receiving as server, connection did not already exist + int authPolicy = this->authPolicy.load(); + if(pktType == 1 && !flags.test(2) + && authPolicy == UDPC_AuthPolicy::UDPC_AUTH_POLICY_STRICT) { + UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_ERROR, + "Client peer ", + UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr), + " port ", + ntohs(receivedData.sin6_port), + " attempted connection with packet authentication " + "enabled, but auth is disabled and AuthPolicy is STRICT"); + return; + } else if(pktType == 0 && flags.test(2) + && authPolicy == UDPC_AuthPolicy::UDPC_AUTH_POLICY_STRICT) { + UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_ERROR, + "Client peer ", + UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr), + " port ", + ntohs(receivedData.sin6_port), + " attempted connection with packet authentication " + "disabled, but auth is enabled and AuthPolicy is STRICT"); + return; + } unsigned char *sk = nullptr; unsigned char *pk = nullptr; if(keysSet.load()) { @@ -1259,6 +1281,32 @@ void UDPC::Context::update_impl() { ", port ", ntohs(receivedData.sin6_port)); return; } + int authPolicy = this->authPolicy.load(); + if(pktType == 2 && !iter->second.flags.test(6) + && authPolicy == UDPC_AuthPolicy::UDPC_AUTH_POLICY_STRICT) { + // This block actually should never happen, because the server + // receives a packet first. If client requests without auth, + // then the server will either deny connection (if strict) or + // fallback to a connection without auth (if fallback). + UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_ERROR, + "Server peer ", + UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr), + " port ", + ntohs(receivedData.sin6_port), + " attempted connection with packet authentication " + "enabled, but auth is disabled and AuthPolicy is STRICT"); + return; + } else if(pktType == 0 && iter->second.flags.test(6) + && authPolicy == UDPC_AuthPolicy::UDPC_AUTH_POLICY_STRICT) { + UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_ERROR, + "Server peer ", + UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr), + " port ", + ntohs(receivedData.sin6_port), + " attempted connection with packet authentication " + "disabled, but auth is enabled and AuthPolicy is STRICT"); + return; + } if(pktType == 2 && flags.test(2) && iter->second.flags.test(6)) { #ifdef UDPC_LIBSODIUM_ENABLED @@ -1300,7 +1348,6 @@ void UDPC::Context::update_impl() { UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_WARNING, "peer is not using libsodium, but peer_pk was " "pre-set, dropping to no-verification mode"); - // TODO set policy for using/not-using libsodium } } @@ -1663,6 +1710,7 @@ UDPC_ConnectionId UDPC_create_id_easy(const char *addrString, uint16_t port) { UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient, int isUsingLibsodium) { UDPC::Context *ctx = new UDPC::Context(false); ctx->flags.set(1, isClient != 0); + ctx->authPolicy.exchange(UDPC_AuthPolicy::UDPC_AUTH_POLICY_FALLBACK); UDPC_CHECK_LOG(ctx, UDPC_LoggingType::UDPC_INFO, "Got listen addr ", UDPC_atostr((UDPC_HContext)ctx, listenId.addr)); @@ -2146,6 +2194,35 @@ int UDPC_unset_libsodium_keys(UDPC_HContext ctx) { return 1; } +int UDPC_get_auth_policy(UDPC_HContext ctx) { + UDPC::Context *c = UDPC::verifyContext(ctx); + if(!c) { + return 0; + } + + return c->authPolicy.load(); +} + +int UDPC_set_auth_policy(UDPC_HContext ctx, int policy) { + UDPC::Context *c = UDPC::verifyContext(ctx); + if(!c) { + return 0; + } + + bool isInRange = false; + for(int i = 0; i < UDPC_AuthPolicy::UDPC_AUTH_POLICY_SIZE; ++i) { + if(policy == i) { + isInRange = true; + break; + } + } + if(!isInRange) { + return 0; + } + + return c->authPolicy.exchange(policy); +} + const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId) { return UDPC_atostr(ctx, connectionId.addr); } diff --git a/src/UDPConnection.h b/src/UDPConnection.h index f64df96..bb9eef1 100644 --- a/src/UDPConnection.h +++ b/src/UDPConnection.h @@ -109,7 +109,20 @@ extern "C" { struct UDPC_Context; typedef struct UDPC_Context *UDPC_HContext; -typedef enum { UDPC_SILENT, UDPC_ERROR, UDPC_WARNING, UDPC_INFO, UDPC_VERBOSE, UDPC_DEBUG } UDPC_LoggingType; +typedef enum { + UDPC_SILENT, + UDPC_ERROR, + UDPC_WARNING, + UDPC_INFO, + UDPC_VERBOSE, + UDPC_DEBUG +} UDPC_LoggingType; + +typedef enum { + UDPC_AUTH_POLICY_FALLBACK=0, + UDPC_AUTH_POLICY_STRICT, + UDPC_AUTH_POLICY_SIZE /// Used internally to get max size of enum +} UDPC_AuthPolicy; /*! * \brief Data identifying a peer via addr, port, and scope_id @@ -474,6 +487,9 @@ int UDPC_set_libsodium_key_easy(UDPC_HContext ctx, unsigned char *sk); int UDPC_unset_libsodium_keys(UDPC_HContext ctx); +int UDPC_get_auth_policy(UDPC_HContext ctx); +int UDPC_set_auth_policy(UDPC_HContext ctx, int value); + const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId); const char *UDPC_atostr(UDPC_HContext ctx, UDPC_IPV6_ADDR_TYPE addr); diff --git a/src/test/UDPC_NetworkTest.c b/src/test/UDPC_NetworkTest.c index 949320b..8e7a0d8 100644 --- a/src/test/UDPC_NetworkTest.c +++ b/src/test/UDPC_NetworkTest.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef UDPC_LIBSODIUM_ENABLED #include @@ -25,6 +26,7 @@ void usage() { puts("-ls - enable libsodium"); puts("-ck - connect to server expecting this public key"); puts("-sk - start with pub/sec key pair"); + puts("-p <\"fallback\" or \"strict\"> - set auth policy"); } void sleep_seconds(unsigned int seconds) { @@ -55,6 +57,8 @@ int main(int argc, char **argv) { const char *seckey_file = NULL; unsigned char pubkey[crypto_sign_PUBLICKEYBYTES]; unsigned char seckey[crypto_sign_SECRETKEYBYTES]; + int authPolicy = UDPC_AUTH_POLICY_FALLBACK; + while(argc > 0) { if(strcmp(argv[0], "-c") == 0) { isClient = 1; @@ -113,6 +117,18 @@ int main(int argc, char **argv) { pubkey_file = argv[0]; --argc; ++argv; seckey_file = argv[0]; + } else if(strcmp(argv[0], "-p") == 0 && argc > 1) { + if(strcmp(argv[1], "fallback") == 0) { + authPolicy = UDPC_AUTH_POLICY_FALLBACK; + --argc; ++argv; + } else if(strcmp(argv[1], "strict") == 0) { + authPolicy = UDPC_AUTH_POLICY_STRICT; + --argc; ++argv; + } else { + printf("ERROR: invalid argument \"%s %s\"\n", argv[0], argv[1]); + usage(); + return 1; + } } else { printf("ERROR: invalid argument \"%s\"\n", argv[0]); usage(); @@ -196,6 +212,14 @@ int main(int argc, char **argv) { puts("Set pubkey/seckey for server"); } + UDPC_set_auth_policy(context, authPolicy); + assert(UDPC_get_auth_policy(context) == authPolicy); + if(authPolicy == UDPC_AUTH_POLICY_FALLBACK) { + puts("Auth policy set to \"fallback\""); + } else if(authPolicy == UDPC_AUTH_POLICY_STRICT) { + puts("Auth policy set to \"strict\""); + } + UDPC_enable_threaded_update(context); unsigned int tick = 0;