diff --git a/CMakeLists.txt b/CMakeLists.txt index b43680b0b..f8f177a10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,19 +347,48 @@ else(JPEG_FOUND) "ZoneMinder requires jpeg but it was not found on your system") endif(JPEG_FOUND) +# LIBJWT +find_package(LibJWT) +if(LIBJWT_FOUND) + set(HAVE_LIBJWT 1) + set(optlibsfound "${optlibsfound} LIBJWT") + list(APPEND ZM_BIN_LIBS "${LIBJWT_LIBRARY}") +else(LIBJWT_FOUND) + set(optlibsnotfound "${optlibsnotfound} LIBJWT") +endif(LIBJWT_FOUND) + +# gnutls (using find_library and find_path) +find_library(GNUTLS_LIBRARIES gnutls) +if(GNUTLS_LIBRARIES) + set(HAVE_LIBGNUTLS 1) + list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}") + find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h) + if(GNUTLS_INCLUDE_DIR) + include_directories("${GNUTLS_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") + endif(GNUTLS_INCLUDE_DIR) + mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR) + check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H) + set(optlibsfound "${optlibsfound} GnuTLS") +else(GNUTLS_LIBRARIES) + set(optlibsnotfound "${optlibsnotfound} GnuTLS") +endif(GNUTLS_LIBRARIES) + # OpenSSL -find_package(OpenSSL) -if(OPENSSL_FOUND) - set(HAVE_LIBOPENSSL 1) - set(HAVE_LIBCRYPTO 1) - list(APPEND ZM_BIN_LIBS "${OPENSSL_LIBRARIES}") - include_directories("${OPENSSL_INCLUDE_DIR}") - set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") - check_include_file("openssl/md5.h" HAVE_OPENSSL_MD5_H) - set(optlibsfound "${optlibsfound} OpenSSL") -else(OPENSSL_FOUND) - set(optlibsnotfound "${optlibsnotfound} OpenSSL") -endif(OPENSSL_FOUND) +if(NOT HAVE_LIBGNUTLS OR NOT HAVE_LIBJWT) + find_package(OpenSSL) + if(OPENSSL_FOUND) + set(HAVE_LIBOPENSSL 1) + set(HAVE_LIBCRYPTO 1) + list(APPEND ZM_BIN_LIBS "${OPENSSL_LIBRARIES}") + include_directories("${OPENSSL_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") + check_include_file("openssl/md5.h" HAVE_OPENSSL_MD5_H) + set(optlibsfound "${optlibsfound} OpenSSL") + else(OPENSSL_FOUND) + set(optlibsnotfound "${optlibsnotfound} OpenSSL") + endif(OPENSSL_FOUND) +endif(NOT HAVE_LIBGNUTLS OR NOT HAVE_LIBJWT) # pthread (using find_library and find_path) find_library(PTHREAD_LIBRARIES pthread) @@ -416,28 +445,6 @@ else(GCRYPT_LIBRARIES) set(optlibsnotfound "${optlibsnotfound} GCrypt") endif(GCRYPT_LIBRARIES) -# gnutls (using find_library and find_path) -find_library(GNUTLS_LIBRARIES gnutls-openssl) -if(NOT GNUTLS_LIBRARIES) - find_library(GNUTLS_LIBRARIES gnutls) -endif(NOT GNUTLS_LIBRARIES) - -if(GNUTLS_LIBRARIES) - set(HAVE_LIBGNUTLS 1) - list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}") - find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h) - if(GNUTLS_INCLUDE_DIR) - include_directories("${GNUTLS_INCLUDE_DIR}") - set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}") - endif(GNUTLS_INCLUDE_DIR) - mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR) - check_include_file("gnutls/openssl.h" HAVE_GNUTLS_OPENSSL_H) - check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H) - set(optlibsfound "${optlibsfound} GnuTLS") -else(GNUTLS_LIBRARIES) - set(optlibsnotfound "${optlibsnotfound} GnuTLS") -endif(GNUTLS_LIBRARIES) - # mysqlclient (using find_library and find_path) find_library(MYSQLCLIENT_LIBRARIES mysqlclient PATH_SUFFIXES mysql) if(MYSQLCLIENT_LIBRARIES) diff --git a/cmake/Modules/FindLibJWT.cmake b/cmake/Modules/FindLibJWT.cmake new file mode 100644 index 000000000..e0c834609 --- /dev/null +++ b/cmake/Modules/FindLibJWT.cmake @@ -0,0 +1,28 @@ +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBJWT QUIET libjwt) + +find_path(LIBJWT_INCLUDE_DIR + NAMES jwt.h + HINTS ${PC_LIBJWT_INCLUDEDIR} ${PC_LIBJWT_INCLUDE_DIRS} + ) + +find_library(LIBJWT_LIBRARY + NAMES jwt-gnutls libjwt-gnutls liblibjwt-gnutls + HINTS ${PC_LIBJWT_LIBDIR} ${PC_LIBJWT_LIBRARY_DIR} + ) + +find_package_handle_standard_args(LibJWT + REQUIRED_VARS LIBJWT_INCLUDE_DIR LIBJWT_LIBRARY + ) + +if(LIBJWT_FOUND) + add_library(libjwt STATIC IMPORTED GLOBAL) + set_target_properties(libjwt PROPERTIES + IMPORTED_LOCATION "${LIBJWT_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LIBJWT_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced(LIBJWT_INCLUDE_DIR LIBJWT_LIBRARY) \ No newline at end of file diff --git a/src/jwt-cpp/include/jwt-cpp/jwt.h b/src/jwt-cpp/include/jwt-cpp/jwt_cpp.h similarity index 100% rename from src/jwt-cpp/include/jwt-cpp/jwt.h rename to src/jwt-cpp/include/jwt-cpp/jwt_cpp.h diff --git a/src/zm_crypt.cpp b/src/zm_crypt.cpp index 6b78e169b..8e42b3b3c 100644 --- a/src/zm_crypt.cpp +++ b/src/zm_crypt.cpp @@ -1,12 +1,81 @@ #include "zm.h" #include "zm_crypt.h" #include "BCrypt.hpp" -#include "jwt.h" +#if HAVE_LIBJWT +#include +#else +#include "jwt_cpp.h" +#endif #include +#if HAVE_LIBCRYPTO #include +#elif HAVE_GNUTLS_GNUTLS_H +#include +#include +#endif #include // returns username if valid, "" if not +#if HAVE_LIBJWT +std::pair verifyToken(std::string jwt_token_str, std::string key) { + std::string username = ""; + unsigned int token_issued_at = 0; + int err = 0; + jwt_t *jwt = nullptr; + + err = jwt_new(&jwt); + if( err ) { + Error("Unable to Allocate JWT object"); + return std::make_pair("", 0); + } + + err = jwt_set_alg(jwt, JWT_ALG_HS256, (const unsigned char*)key.c_str(), key.length()); + if( err ) { + jwt_free(jwt); + Error("Error setting Algorithm for JWT decode"); + return std::make_pair("", 0); + } + + err = jwt_decode(&jwt, jwt_token_str.c_str(), nullptr, 0); + if( err ) { + jwt_free(jwt); + Error("Could not decode JWT"); + return std::make_pair("", 0); + } + + const char *c_type = jwt_get_grant(jwt, (const char*)"type"); + if ( !c_type ) { + jwt_free(jwt); + Error("Missing token type. This should not happen"); + return std::make_pair("", 0); + } else if ( std::string(c_type) != "access" ) { + jwt_free(jwt); + Error("Only access tokens are allowed. Please do not use refresh tokens"); + return std::make_pair("", 0); + } + + const char *c_username = jwt_get_grant(jwt, (const char*)"user"); + if( !c_username ) { + jwt_free(jwt); + Error("User not found in claim"); + return std::make_pair("", 0); + } + + username = std::string(c_username); + Debug(1, "Got %s as user claim from token", username.c_str()); + + token_issued_at = (unsigned int)jwt_get_grant_int(jwt, "iat"); + if ( errno == ENOENT ) { + jwt_free(jwt); + Error("IAT not found in claim. This should not happen"); + return std::make_pair("", 0); + } + + Debug(1, "Got IAT token=%u", token_issued_at); + jwt_free(jwt); + return std::make_pair(username, token_issued_at); +} +#else // HAVE_LIBJWT std::pair verifyToken(std::string jwt_token_str, std::string key) { std::string username = ""; unsigned int token_issued_at = 0; @@ -58,6 +127,7 @@ std::pair verifyToken(std::string jwt_token_str, std } return std::make_pair(username, token_issued_at); } +#endif // HAVE_LIBJWT bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) { bool password_correct = false; @@ -70,10 +140,16 @@ bool verifyPassword(const char *username, const char *input_password, const char // MYSQL PASSWORD Debug(1, "%s is using an MD5 encoded password", username); - SHA_CTX ctx1, ctx2; + #ifndef SHA_DIGEST_LENGTH + #define SHA_DIGEST_LENGTH 20 + #endif + unsigned char digest_interim[SHA_DIGEST_LENGTH]; unsigned char digest_final[SHA_DIGEST_LENGTH]; - + +#if HAVE_LIBCRYPTO + SHA_CTX ctx1, ctx2; + //get first iteration SHA1_Init(&ctx1); SHA1_Update(&ctx1, input_password, strlen(input_password)); @@ -83,6 +159,15 @@ bool verifyPassword(const char *username, const char *input_password, const char SHA1_Init(&ctx2); SHA1_Update(&ctx2, digest_interim,SHA_DIGEST_LENGTH); SHA1_Final (digest_final, &ctx2); +#elif HAVE_GNUTLS_GNUTLS_H + //get first iteration + gnutls_hash_fast(GNUTLS_DIG_SHA1, input_password, strlen(input_password), digest_interim); + //2nd iteration + gnutls_hash_fast(GNUTLS_DIG_SHA1, digest_interim, SHA_DIGEST_LENGTH, digest_final); +#else + Error("Authentication Error. ZoneMinder not built with GnuTLS or Openssl"); + return false; +#endif char final_hash[SHA_DIGEST_LENGTH * 2 +2]; final_hash[0] = '*'; diff --git a/src/zm_rtsp_auth.h b/src/zm_rtsp_auth.h index 34056eee6..8e65746de 100644 --- a/src/zm_rtsp_auth.h +++ b/src/zm_rtsp_auth.h @@ -19,9 +19,6 @@ #ifndef ZM_RTSP_AUTH_H #define ZM_RTSP_AUTH_H -#if HAVE_GNUTLS_OPENSSL_H -#include -#endif #if HAVE_GNUTLS_GNUTLS_H #include #endif diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 1ebd3f1ff..1c0eb6d51 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -27,9 +27,6 @@ #include #include -#if HAVE_GNUTLS_OPENSSL_H -#include -#endif #if HAVE_GNUTLS_GNUTLS_H #include #endif diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 46cf28d46..320620aa0 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -38,7 +38,6 @@ #cmakedefine HAVE_LIBGCRYPT 1 #cmakedefine HAVE_GCRYPT_H 1 #cmakedefine HAVE_LIBGNUTLS 1 -#cmakedefine HAVE_GNUTLS_OPENSSL_H 1 #cmakedefine HAVE_GNUTLS_GNUTLS_H 1 #cmakedefine HAVE_LIBMYSQLCLIENT 1 #cmakedefine HAVE_MYSQL_H 1 @@ -66,6 +65,7 @@ #cmakedefine HAVE_MP4_H 1 #cmakedefine HAVE_MP4V2_H 1 #cmakedefine HAVE_MP4V2_MP4V2_H 1 +#cmakedefine HAVE_LIBJWT 1 /* Authenication checks */ #cmakedefine HAVE_MD5_OPENSSL 1